UI.Utils

Swiss-Army-Knife of AngularJS tools (with no external dependencies!)

Code on Github Download (0.1.1)

What?

Bind a callback to any event not natively supported by Angular.

Why?

For Blurs, Focus, Double-Clicks or any other event you may choose that isn't built-in.

How?

You can pass multiple events as an object, along with the jQuery event itself:

<input ui-event="{ blur : 'blurCallback($event)' }">

<script>
$scope.blurCallback = function(evt) {
alert('Goodbye. Input content is: ' + evt.target.value);
};
</script>

What?

Replace tokens in a string in a variety of ways

{{ sentence | format : tokens[mode] }}

Tokens: {{ tokens[mode] | json }}

Why?

Most commonly, this filter is helpful for internationalization. However anywhere you need to do string replacement the format filter will come in handy.

How?

{{ "Hello $0, how are you?" | format : 'Bob' }}
-- or --
$scope.tokens = ['first','second','third'];
...
{{ "Are you on the $0, $1 or $2?" | format : tokens }}
-- or --
$scope.tokens = { name:'Bob', subject:'wife' };
...
{{ "Hey :name, how's the :subject?" | format : tokens }}

What?

Easily highlight some text in a block

How?

<label><input type="checkbox" ng-model="caseSensitive"> Case Sensitive?</label>
<input placeholder="Enter some text to highlight" value="you" ng-model="highlightText">
<p ng-bind-html="'Hello there, how are you today? I\'m fine thank you.' | highlight:highlightText:caseSensitive"></p>

<style>
.ui-match { background: yellow; }
</style>

What?

uiInclude is an alternative to ngInclude that adds fragment support via a fragment attribute. The fragment attribute uses the element.find() API, and therefore requires jQuery in order to support full CSS selectors; Without jQuery, it falls back to Angular's jqLite implementation which is very limited as it only selects by element name.

Why?

Use this instead of ngInclude only if you need fragments. Fragment support has two primary uses: (1) it serves as a drop in replacement for jQuery.load(), which permits a subset of a requested document to be selected, and (2) because some people want to put multiple templates into a single file and they need a way to select which specific fragment to use. The former use is expected to be benefit projects that are migrating from jQuery to Angular.

Demo

Choose fragment to load:
Fragment content (fragment="'{{uiIncludeFragment}}'"):

How?

<ui-include src="'my/url/to/partial/file'" fragment="'#id-to-fragment'"></ui-include>
<!-- Don't forget to quote string literals! -->
<!-- Don't forget to include jQuery if you need full selector support! -->

What?

Provides an easy way to toggle a checkbox input's special 'indeterminate' property. This is a visual toggle only and in no way affects the model or value outside of native browser behavior at this time.


Why?

Convenience.

How?

Indeterminate: <input type="checkbox" ui-indeterminate="isKnown" readonly>
Toggle indeterminate here: <input type="checkbox" ng-model="isKnown">

What?

Converts a string to an alternative format.

{{inflectorText|inflector:inflectorType}}

How?

<label><input type="radio" value="humanize" ng-model="inflectorType"> Humanize (Default)</label>
<label><input type="radio" value="underscore" ng-model="inflectorType"> Underscore</label>
<label><input type="radio" value="variable" ng-model="inflectorType"> Variable</label>

<input placeholder="Enter some text to inflect" ng-model="inflectorText">
<p>{{inflectorText|inflector:inflectorType}}</p>

<script>
$scope.inflectorText = 'Here Is my_phoneNumber';
$scope.inflectorType = 'humanize';
</script>

What?

Call the jQuery function or plugin specified on the element.

This example shows how to call the bootstrap tooltip with almost no work:

Why?

Not every jQuery plugin requires creating a new directive just to use it. Instead, use the pass-through directive to rapidly port functionality. It is probably the best solution for 75% of the cases you will encounter.

If a plugin requires more robust integration with AngularJS then you may need to look into creating a custom directive instead, or contact us with a request.

How?

To call something like $.fn.tooltip() simply do ui-jq="tooltip". Note that the name of the function must be identical. This also works for normal jQuery commands such as $.fn.slideUp().

To pass parameters use the ui-options attribute. The value will be evaluated in the $scope context and passed to the function. If defaults are set, the passed options will extend them. If a string is passed, the default options will be ignored.

Use the directive name jq for namespacing inside uiJqConfig. Then sub-namespace options for each function by the name of that function (exactly as it is passed to ui-jq) so that you don't have to pass options every time you call the directive.

<a title="Easiest. Binding. Ever!" ui-jq="tooltip">Hover over me for static Tooltip</a>

<a data-original-title="{{tooltip}}" ui-jq="tooltip">Fill the input for a dynamic Tooltip:</a>
<input type="text" ng-model="tooltip" placeholder="Tooltip Content">

<script>
    myModule.value('uiJqConfig', {
        // The Tooltip namespace
        tooltip: {
             // Tooltip options. This object will be used as the defaults
            placement: 'right'
        }
    });
</script>

What?

Bind an event to a particular keypress

Click inside this div and hit [Enter]. You can make any element accept keyboard event by adding tabindex="0" attribute to the element.

Why?

Cuz you feel like it? Maybe I should stop doing the 'Why' sections, running out of explanations...

How?

The directive takes a hash (object) with the key code as the key and the callback function to fire as the value. The callback function takes an 'event' param

Note that 13 represents the RETURN key code.

<textarea
        ui-keypress="{13:'keypressCallback($event)'}">
</textarea>
<textarea
        ui-keydown="{'enter alt-space':'keypressCallback($event)'}">
</textarea>
<textarea
        ui-keyup="{'enter':'keypressCallback($event)'}">
</textarea>
<div tabindex="0"
    ui-keyup="{'enter':'keypressCallback($event)'}">
</div>

<script>
    $scope.keypressCallback = function($event) {
        alert('Voila!');
        $event.preventDefault();
    };
</script>

uiMask Directive Demo

Model value: {{ x }}
Model value: undefined
NgModelController.$viewValue: {{ demo.masked.$viewValue }}
NgModelController.$viewValue: undefined
A Any letter.
9 Any number.
* Any letter or number.

How?

TODO !!


    

What?

Adds an icon or link that empties the input element

Resets to empty:    

Resets to "Empty":

Remember that you control the CSS. Make the icon always show by changing the CSS to match the :hover state.

How?

You can set an app-wide reset value using ui.config

<input ng-model="resetModel" ui-reset>
<input ng-model="resetModel" ui-reset=" 'Empty' ">

<script>
    $scope.resetModel = 'Hover over me';
</script>

What?

Route Matching Magic. It matches your routes ... magically!

Clicking "Make Active" will reload the page. Pay attention to the routes.

  • uiRoute Info IS is NOT active.
  • Route {{ route }} IS is NOT active. Make Active

Why?

It would be nice if your app knew what the address path was and acted accordingly, right? Right.

Options

  • Out of the box this directive ships with a boolean to determine if the route matches or not: $uiRoute.
    • Example Usage: <a ui-route="/page" ng-class="{active: $uiRoute}">link</a>
  • Using ui-route as an attribute with value supports the following:
    • Static: <a ui-route="/page">
    • Regular Expression: <a ui-route="/page/[0-9]*">
    • Template Vars: <a ui-route="/page/{{ sample }}">
    • Template Vars && RegEx: <a ui-route="/page/{{ sample }}/[0-9]*">
  • Using ui-route with ng-href attribute:
    • Static: <a ui-route ng-href="/page">
    • Template Vars: <a ui-route ng-href="/page/{{ sample }}">
  • Using ui-route with href attribute:
    • Static Only: <a ui-route href="/page">
  • You can also pass a model to ui-route. This model could then be used the same as $uiRoute.
    • <li ui-route="/page/{{ sample }}" ng-model="current">

How?

<ul>
<li ui-route="#/route-1">Route 1
<strong ng-show="$uiRoute">IS</strong>
<strong ng-show="!$uiRoute">is NOT</strong> active.
</li>
<li ui-route="#/route-2">Route 2
<strong ng-show="$uiRoute">IS</strong>
<strong ng-show="!$uiRoute">is NOT</strong> active.
</li>
<li ui-route="#/route-3">Route 3
<strong ng-show="$uiRoute">IS</strong>
<strong ng-show="!$uiRoute">is NOT</strong> active.
</li>
</ul>

What?

Provide access to scrollable lists of unlimited length.

Items can be of any complexity and can vary in any possible way. They are dynamically instantiated as they become visible and $destroyed as they are scrolled out of view.

{{$index + ' ' + item}}

Why?

The common way to present to the user a list of data elements of undefined length is to start with a small portion at the top of the list - just enough to fill the space on the page. Additional rows are appended to the bottom of the list as the user scrolls down the list.

Unfortunately, even though rows at the top of the list become invisible as they scroll out of the view, they are still a part of the page and still consume resources. As the user scrolls down the list grows and the web app slows down.

read more...

How?

If all you want to use the entire window as the viewport, all you need is this:

<div ui-scroll="item in datasource">{{item}}</div>

If you want to control the viewport yourself you can do it like this:

<div ui-scroll-viewport style="height:200px;" >
   <div ui-scroll="item in datasource">{{item}}</div>
</div>

Make sure that you always constrain the height of your viewport

What?

Add a 'ui-fixed' class to elements when the page scrolls past them

They see me scrollin...

Try scrolling past the red text or changing the offset

Why?

Make elements sticky, or simply appear different after scrolling past a certain point

Remember that this directive only adds a ui-scrollfix class to the element. It is up to you to add the corresponding CSS rules, however it also gives you the ability to add other rules instead if you prefer.

How?

<p ui-scrollfix>They see me scrollin...</p>

You can optionally pass a number to ui-scrollfix which would override the detected y-offset of the element. Values can be either absolute 600 or offset from the calculated value -50 or +100.

What?

Instead of doing ng-show and ng-hide which simply sets display:block/none a ui-show and ui-hide class will be added which can give you tighter control over how things appear or disappear.

Why?

CSS3 transitions of course! Applying a class means you can specify exactly how these two states behave. In addition, the show/hide variants do not enforce css rules when they are false (unless you use toggle), so the default CSS can still apply.

But can't you just do ng-class="{ ui-show : someExpression }"?

... shutup.

In all seriousness, this is just a convenience wrapper for using ng-class. This way you can simply swap out instances of ng for ui to immediately get your customized approach.

How?

<p><a ng-click="showHide=!showHide">Toggle State: {{!!showHide}}</a></p>
<div ui-show="showHide">Show</div>
<div ui-hide="showHide">Hide</div>
<div ui-toggle="showHide">Toggle</div>

<style>
.ui-show {
  color: blue;
  transition: all 0.5s ease; /* You should probably browser-prefix this */
}
.ui-hide {
  opacity: 0;
  transition: all 0.5s ease; /* You should probably browser-prefix this */
}
</style>

Using ui-show or ui-hide will add a class of the same name when the expression is true.

Use ui-toggle if you want to leverage both classes, as ui-show will be added when true and ui-hide when false.

What?

Filters out all duplicate objects items from an array by checking the specified key

Select an attribute to check for uniqueness

{{items | unique:attribute | json}}

How?

The filter can take the name of the key to check for uniqueness or set to a non-string truthy value to check the entire object.

<select ng-model="attribute">
<option value="">-- No Filter --</option>
<option>firstName</option>
<option>lastName</option>
<option>id</option>
<option>gender</option>
</select>
<pre>{{items | unique:attribute | json}}</pre>

<script>
$scope.items = [
{ firstName: 'Dean', lastName: 'Sofer',
id: 1, gender: 'Male' },
{ firstName: 'Dean', lastName: 'Kuntz',
id: 2, gender: 'Male' },
{ firstName: 'Peter', lastName: 'Piper',
id: 3, gender: 'Female' },
{ firstName: 'Peter', lastName: 'Darwin',
id: 4, gender: 'Male' },
{ firstName: 'Janet', lastName: 'Piper',
id: 5, gender: 'Female' },
{ firstName: 'Dan', lastName: 'Doyon',
id: 6, gender: 'Male' },
{ firstName: 'Andy', lastName: 'Joslin',
id: 1, gender: 'Male' },
];
</script>

What?

The ui-validate directive makes it very easy to create custom validator expressions.

e-mail

This e-mail is black-listed!
is form valid: {{form.$valid}}
email errors: {{form.email.$error | json}}

password

Passwords do not match!
is form valid: {{form.$valid}}
password errors: {{form.confirm_password.$error | json}}

Why?

AngularJS comes with several built-in validation mechanism for input fields (ngRequired, ngPattern etc.) but using an arbitrary validation function requires creation of custom formatters and / or parsers. The ui-validate directive makes it easy to use any function(s) defined in scope as a validator function(s).

<input name="email" ng-model="email"
ui-validate="{blacklist : 'notBlackListed($value)' }">
Is e-mail black-listed? {{!!form.email.$error.blacklist}}

<input name="password" required ng-model="password">
<input name="confirm_password"
ui-validate=" '$value==password' "
ui-validate-watch=" 'password' ">
Passwords match? {{!!form.confirm_password.$error.validator}}

...

$scope.notBlackListed = function(value) {
var blacklist = ['bad@domain.com','verybad@domain.com'];
return blacklist.indexOf(value) === -1;
}

How?

Create an expression inside a string. If it evaluates to true the input is valid, the rule name will be validator by default.

ui-validate=" 'validateFoo($value)' "
Input is valid: {{!!myForm.myInput.$error.validator}}

Or define multiple rules by creating an object where the key is the rule name and the value is the expression string.

ui-validate="{foo:'valFoo($value)', bar:'$value == someVar'}"
Foo rule passes: {{!!myForm.myInput.$error.foo}}
Bar rule passes: {{!!myForm.myInput.$error.bar}}