Core UI Functionalities are those any HTML UI built on Angular could use. They are not Mobile-specific nor depending on anything else that Angular itself, and you could use them with any css framework.
They are the same that 1.1 beside to be prefixed with ui-
so use: ui-yield-to
and ui-content-for
.
Toggle has been rewritten from scratch for 1.2. In place of that there is a new service with it's own isolated context.
It is called SharedState
. It will act as a BUS between UI elements to share UI related state that is automatically disposed when all scopes requiring it are destroyed.
eg.
SharedState.initialize(requiringScope, 'myId');
SharedState.toggle('myId');
Using SharedState
directives is very close to attach an ng-init
in root element and interact through expression and ng-click, but it has handy features to avoid polluting controllers/scopes with ui-related stuffs.
SharedState
methods are exposed through ui-
directives. So you should never use it directly in your controller, and you can spare them to hold application logic.
Example: Tabs
<div class="tabs" ui-state="activeTab">
<ul class="nav nav-tabs">
<li ui-class="{'active': activeTab == 1)}">
<a ui-set="{'activeTab': 1}">Tab 1</a>
</li>
<li ui-class="{'active': activeTab == 2)}">
<a ui-set="{'activeTab': 2}">Tab 2</a>
</li>
<li ui-class="{'active': activeTab == 3)}">
<a ui-set="{'activeTab': 3}">Tab 3</a>
</li>
</ul>
<div ui-if="activeTab == 1">
Tab 1
</div>
<div ui-if="activeTab == 2">
Tab 2
</div>
<div ui-if="activeTab == 3">
Tab 3
</div>
</div>
NOTE: ui-toggle/set/turnOn/turnOff
responds to click/tap
without stopping propagation so you can use them along with ng-click too. You can also change events to respond to with ui-triggers
attribute.
Any SharedState
method is exposed through Ui
object in $rootScope
. So you could always do ng-click="Ui.turnOn('myVar')"
.
Since SharedState
is a service you can initialize/set statuses through controllers too:
app.controller('myController', function($scope, SharedState){
SharedState.initialize($scope, "activeTab", 3);
});
As well as you can use ui-default
for that:
<div class="tabs" ui-state="activeTab" ui-default="thisIsAnExpression(5 + 1 - 2)"></div>
ui-outer-click
and ui-outer-click-if
are directives that allow to specifiy a behaviour when click/tap events happen outside an element. This can be easily used to implement eg. close on outer click feature for a dropdown.
<div class="btn-group pull-right">
<a ui-turn-on='myDropdown' class='btn'>
<i class="fa fa-ellipsis-v"></i>
</a>
<ul
class="dropdown-menu"
ui-state="myDropdown"
ui-if="myDropdown"
ui-outer-click="ui.turnOff('myDropdown')"
ui-outer-click-if="ui.active('myDropdown')"
ui-turn-off="myDropdown">
<li><a>Action</a></li>
<li><a>Another action</a></li>
<li><a>Something else here</a></li>
<li class="divider"></li>
<li><a>Separated link</a></li>
</ul>
</div>
$drag
Service wraps ngTouch
's $swipe
to extend its behavior moving one or more
target element through css transform according to the $swipe
coords thus creating
a drag effect.
$drag interface is similar to $swipe
:
app.controller('MyController', function($drag, $element){
$drag.bind($element, {
start: function(coords, cancel, markers, e){},
move: function(coords, cancel, markers, e){},
end: function(coords, cancel, markers, e){},
cancel: function(coords, markers, e){},
transform: function(x, y, transform) {},
adaptTransform: function(x, y, transform) {},
constraint: fn or {top: y1, left: x1, bottom: y2, right: x2}
});
});
Main differences with $swipe
are:
- coords param take into account css transform so you can easily detect collision with other elements.
- start, move, end callback receive a cancel funcion that can be used to cancel the motion and reset the transform.
- you can configure the transform behavior passing a transform function to options.
- you can constraint the motion through the constraint option (setting relative movement limits) or through the track option (setting absolute coords);
- you can setup collision markers being watched and passed to callbacks.
Example (drag to dismiss):
$drag.bind(e, {
move: function(c, cancel, markers){
if(c.left > markers.m1.left) {
e.addClass('willBeDeleted');
} else {
e.removeClass('willBeDeleted');
}
},
end: function(coords, cancel){
if(c.left > markers.m1.left) {
e.addClass('deleting');
delete($scope.myModel).then(function(){
e.remove();
}, function(){
cancel();
});
} else {
cancel();
}
},
cancel: function(){
e.removeClass('willBeDeleted');
e.removeClass('deleting');
},
constraint: {
minX: 0,
minY: 0,
maxY: 0
},
});
Transform
is the underlying service used by $drag
to deal with css trasform matrix in a simpler and vendor-angnostic way.
<div id="myElem" style="transform: translateX: 20px;"></div>
var e = document.getElementById('myElem');
var t0 = Transform.fromElement(e);
console.log(t0.getTranslation().x);
// -> 20;
t0.rotate(90);
// Set t0 to element ignoring previous transform.
t0.set(e);
var t1 = new Transform();
t1.translate(12, 40);
// merges t1 with current trasformation matrix of element.
t1.apply(e);
Since 1.2 I've tried to retain bootstrap existing components look and feel as much as possible for two reason:
- People would expect to already know them and how customize them with css.
- Mobile Angular UI dependance on bootstrap is more loose so it does not need to be updated each time BS3 changes.
As a consequence i've reduced special style for panels/forms/modals to the bare minimum.
Pretty much the same. They plays well with ng-if
now.
.scrollable
component is backward compatible but also has some major improvements too.
.scrollable-header/.scrollable-footer
can be used to add fixed header/footer to a scrollable area without having to deal with css height and positioning to avoid breaking scroll..scrollable-content
controller now expose ascrollTo
function.- It plays nice with android keyboard and forms.
- You can use
ui-scroll-bottom/ui-scroll-top
directives handle that events and implement features like infinite scroll.
<div class="scrollable">
<div class="scrollable-content section" ui-scroll-bottom="loadMore()">
<ul>
<li ng-repeat="item in items">
{{item.name}}
</li>
</ul>
</div>
</div>
Modal dialogs has been reintroduced from Bootstrap, overlays are now just modals styled different.
<div content-for="modals">
<!-- A plain modal dialog -->
<div class="modal" ui-if='modal1' ui-state='modal1'>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close"
ui-turn-off="modal1">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>{{lorem}}</p>
</div>
<div class="modal-footer">
<button ui-turn-off="modal1" class="btn btn-default">Close</button>
<button ui-turn-off="modal1" ng-click="doSomething()" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<!-- A blurred overlay dialog -->
<div class="modal modal-overlay" ui-if='modal2' ui-state='modal2'>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close"
ui-turn-off="modal2">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p>{{lorem}}</p>
</div>
<div class="modal-footer">
<button ui-turn-off="modal2" class="btn btn-default">Close</button>
<button ui-turn-off="modal2" ng-click="doSomething()" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
Basically the same, but now they rely on SharedState
and bindOuterClick
to activate/inactivate them.
Syntax is basically the same:
<div class="sidebar sidebar-left">
<!-- ... -->
</div>
Also you can now track sidebars status in url specifing uiTrackAsSearchParam
attribute. This way you can manage to close a sidebar on back button too. It is optional cause it has a big caveat: you should not use query string part to update your view automatically. It is safe for many apps but not for all, so its optional.
To use this feature:
- enable it in sidebar setting
uiTrackAsSearchParam
totrue
:
<div class="sidebar sidebar-left" ui-track-as-search-param="true">
<!-- ... -->
</div>
- Specify
reloadOnSearch: false
on your routes:
app.config(function($routeProvider) {
$routeProvider.when('/', {templateUrl: 'home.html', reloadOnSearch: false});
$routeProvider.when('/scroll', {templateUrl: 'scroll.html', reloadOnSearch: false});
$routeProvider.when('/toggle', {templateUrl: 'toggle.html', reloadOnSearch: false});
$routeProvider.when('/tabs', {templateUrl: 'tabs.html', reloadOnSearch: false});
$routeProvider.when('/accordion', {templateUrl: 'accordion.html', reloadOnSearch: false});
$routeProvider.when('/overlay', {templateUrl: 'overlay.html', reloadOnSearch: false});
$routeProvider.when('/forms', {templateUrl: 'forms.html', reloadOnSearch: false});
$routeProvider.when('/dropdown', {templateUrl: 'dropdown.html', reloadOnSearch: false});
$routeProvider.when('/drag', {templateUrl: 'drag.html', reloadOnSearch: false});
$routeProvider.when('/carousel', {templateUrl: 'carousel.html', reloadOnSearch: false});
});
Carousel implementations (with $swipe
or $drag
) has been moved in an external file/plugin and not included by default.
panels
and forms
has been discontinued completely. This is due to: panels has a trivial markup as they are in bootstrap. Forms on the contrary has a lot of functionalities so in my opinion .form-*
directives need an external plugin to be implemented and mantained correctly.
Hello,
First of all, thank you very much for the update. I would like to mention that ng-click did not actually work from a modal when used simultaneously with ui-turn-off.