diff --git a/.travis.yml b/.travis.yml index 035577a84..85f22356c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,12 @@ language: node_js node_js: - "5.9" env: - - CXX=g++-4.8 + global: + - CXX=g++-4.8 + - GH_REF: github.com/angular-ui/ui-select.git + - GH_PAGES_BRANCH: gh-pages + - secure: "PkIhXXwrR5fHh7fH+2WizaY0MmK1l1Dr7PCqs112PkEimVPcntRJeA5pjTwGRwHm+RSkFVtfo38EY/GUwzhLSRTO7WZ+id+vIMGQLgiofqrOwi0nq93esG6qI8Jg5K0GUt8mzg5m9B2tgm2I91RAojEhIukKcbsDsq3hNAUy71Y=" + addons: apt: sources: @@ -16,6 +21,19 @@ before_script: - npm install --quiet -g gulp script: "gulp test" + +after_success: + - "gulp docs" + +deploy: + skip_cleanup: true + provider: "script" + script: "bash ./deploy-docs.sh" + on: + all_branches: true +# on: +# tags: true + sudo: false git: diff --git a/README.md b/README.md index 10e97ea56..8034f1151 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,43 @@ -# AngularJS ui-select [](https://travis-ci.org/angular-ui/ui-select) +# AngularJS ui-select [](https://travis-ci.org/angular-ui/ui-select) [](https://gitter.im/angular-ui/ui-select?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[](https://gitter.im/angular-ui/ui-select?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +AngularJS-native version of [Select2](http://ivaynberg.github.io/select2/) and [Selectize](http://brianreavis.github.io/selectize.js/). [http://angular-ui.github.io/ui-select/](http://angular-ui.github.io/ui-select/) -AngularJS-native version of [Select2](http://ivaynberg.github.io/select2/) and [Selectize](http://brianreavis.github.io/selectize.js/). +[Getting Started](https://github.com/angular-ui/ui-select/wiki/Getting-Started) -[Getting Started](https://github.com/angular-ui/ui-select/wiki/Getting-Started) `bower install angular-ui-select` - -- [Demo](http://plnkr.co/edit/a3KlK8dKH3wwiiksDSn2?p=preview) -- [Demo Multiselect](http://plnkr.co/edit/juqoNOt1z1Gb349XabQ2?p=preview) -- [Examples](https://github.com/angular-ui/ui-select/blob/master/examples) +- [Examples](http://angular-ui.github.io/ui-select/#examples) +- [Examples Source](./docs/examples) - [Documentation](https://github.com/angular-ui/ui-select/wiki) -## Last Changes +## Latest Changes - Check [CHANGELOG.md](/CHANGELOG.md) ## Features -- Search, Select, and Multi-select -- Themes: Bootstrap, Select2 and Selectize +- Search, Select, Multi-select and Tagging +- Multiple Themes: Bootstrap, Select2 and Selectize - Keyboard support -- jQuery not required (except for old browsers) +- No jQuery required (except for old browsers) - Small code base: 4.57KB min/gzipped vs 20KB for select2 For the roadmap, check [issue #3](https://github.com/angular-ui/ui-select/issues/3) and the [Wiki page](https://github.com/angular-ui/ui-select/wiki/Roadmap). -## Installation using [Composer](http://getcomposer.org/) - -Make sure composer is install globally before we proceed. After that we need to add below piece of code in `composer.json` file located inside your project root folder. +## Installation Methods +### npm ``` -{ - "require": { - "components/ui-select": "dev-master" - } -} +$ npm install angular-ui-select +``` +### bower +``` +$ bower install angular-ui-select ``` - -- Run `composer update` and composer will install the component. -- Inside your HTML add below script and link tags. - - select.js: `` - - select.css: `` - ## Development ### Prepare your environment * Install [Node.js](http://nodejs.org/) and NPM (should come with) -* Install global dev dependencies: `npm install -g bower gulp` +* Install global dev dependencies: `npm install -g gulp` * Install local dev dependencies: `npm install` in repository directory ### Development Commands @@ -56,11 +46,12 @@ Make sure composer is install globally before we proceed. After that we need to * `gulp build` to jshint and build * `gulp test` for one-time test with karma (also build and jshint) * `gulp watch` to watch src files to jshint, build and test when changed +* `gulp docs` build docs and examples ## Contributing - Check [CONTRIBUTING.md](/CONTRIBUTING.md) - Run the tests -- Try the [examples](https://github.com/angular-ui/ui-select/blob/master/examples) +- Try the [examples](./docs/examples) When issuing a pull request, please exclude changes from the "dist" folder to avoid merge conflicts. diff --git a/deploy-docs.sh b/deploy-docs.sh new file mode 100644 index 000000000..f18e63a73 --- /dev/null +++ b/deploy-docs.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +[[ $TRAVIS_SECURE_ENV_VARS == "true" ]] || { echo "No github key avaliable, aborting publishing"; exit 0; } + +ID_REF="$(git rev-parse --short HEAD)" + +git clone "https://${GH_KEY}@${GH_REF}" ./docs-out -b ${GH_PAGES_BRANCH} --single-branch --depth=1 + +cd docs-out + +# clear out everything +git rm -rf . +git clean -fxd + +# get new content +cp ../docs-built/* . -R + +git add . + +# inside this git repo we'll pretend to be a new user +git config user.name "Travis CI" +git config user.email "travisci@users.noreply.github.com" + +# The first and only commit to this new Git repo contains all the +# files present with the commit message "Deploy to GitHub Pages". +git commit -m "docs(*): new deploy (angular-ui/ui-select@${ID_REF})" + + +git push origin --quiet +#> /dev/null 2>&1 \ No newline at end of file diff --git a/docs/assets/app.js b/docs/assets/app.js new file mode 100644 index 000000000..f51f062db --- /dev/null +++ b/docs/assets/app.js @@ -0,0 +1 @@ +var module = angular.module('ui.select.pages', ['plunkr']); diff --git a/examples/demo.js b/docs/assets/demo.js similarity index 86% rename from examples/demo.js rename to docs/assets/demo.js index 6922fcf8b..7aaf3364e 100644 --- a/examples/demo.js +++ b/docs/assets/demo.js @@ -40,37 +40,39 @@ app.filter('propsFilter', function() { }; }); -app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) { - $scope.disabled = undefined; - $scope.searchEnabled = undefined; +app.controller('DemoCtrl', function ($scope, $http, $timeout, $interval) { + var vm = this; - $scope.setInputFocus = function (){ + vm.disabled = undefined; + vm.searchEnabled = undefined; + + vm.setInputFocus = function (){ $scope.$broadcast('UiSelectDemo1'); }; - $scope.enable = function() { - $scope.disabled = false; + vm.enable = function() { + vm.disabled = false; }; - $scope.disable = function() { - $scope.disabled = true; + vm.disable = function() { + vm.disabled = true; }; - $scope.enableSearch = function() { - $scope.searchEnabled = true; + vm.enableSearch = function() { + vm.searchEnabled = true; }; - $scope.disableSearch = function() { - $scope.searchEnabled = false; + vm.disableSearch = function() { + vm.searchEnabled = false; }; - $scope.clear = function() { - $scope.person.selected = undefined; - $scope.address.selected = undefined; - $scope.country.selected = undefined; + vm.clear = function() { + vm.person.selected = undefined; + vm.address.selected = undefined; + vm.country.selected = undefined; }; - $scope.someGroupFn = function (item){ + vm.someGroupFn = function (item){ if (item.name[0] >= 'A' && item.name[0] <= 'M') return 'From A - M'; @@ -80,19 +82,19 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) { }; - $scope.firstLetterGroupFn = function (item){ + vm.firstLetterGroupFn = function (item){ return item.name[0]; }; - $scope.reverseOrderFilterFn = function(groups) { + vm.reverseOrderFilterFn = function(groups) { return groups.reverse(); }; - $scope.personAsync = {selected : "wladimir@email.com"}; - $scope.peopleAsync = []; + vm.personAsync = {selected : "wladimir@email.com"}; + vm.peopleAsync = []; $timeout(function(){ - $scope.peopleAsync = [ + vm.peopleAsync = [ { name: 'Adam', email: 'adam@email.com', age: 12, country: 'United States' }, { name: 'Amalie', email: 'amalie@email.com', age: 12, country: 'Argentina' }, { name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina' }, @@ -106,20 +108,20 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) { ]; },3000); - $scope.counter = 0; - $scope.onSelectCallback = function (item, model){ - $scope.counter++; - $scope.eventResult = {item: item, model: model}; + vm.counter = 0; + vm.onSelectCallback = function (item, model){ + vm.counter++; + vm.eventResult = {item: item, model: model}; }; - $scope.removed = function (item, model) { - $scope.lastRemoved = { + vm.removed = function (item, model) { + vm.lastRemoved = { item: item, model: model }; }; - $scope.tagTransform = function (newTag) { + vm.tagTransform = function (newTag) { var item = { name: newTag, email: newTag.toLowerCase()+'@email.com', @@ -130,7 +132,7 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) { return item; }; - $scope.peopleObj = { + vm.peopleObj = { '1' : { name: 'Adam', email: 'adam@email.com', age: 12, country: 'United States' }, '2' : { name: 'Amalie', email: 'amalie@email.com', age: 12, country: 'Argentina' }, '3' : { name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina' }, @@ -143,13 +145,13 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) { '10' : { name: 'Nicolás', email: 'nicolas@email.com', age: 43, country: 'Colombia' } }; - $scope.person = {}; + vm.person = {}; - $scope.person.selectedValue = $scope.peopleObj[3]; - $scope.person.selectedSingle = 'Samantha'; - $scope.person.selectedSingleKey = '5'; + vm.person.selectedValue = vm.peopleObj[3]; + vm.person.selectedSingle = 'Samantha'; + vm.person.selectedSingleKey = '5'; - $scope.people = [ + vm.people = [ { name: 'Adam', email: 'adam@email.com', age: 12, country: 'United States' }, { name: 'Amalie', email: 'amalie@email.com', age: 12, country: 'Argentina' }, { name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina' }, @@ -162,23 +164,23 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) { { name: 'Nicolás', email: 'nicolas@email.com', age: 43, country: 'Colombia' } ]; - $scope.availableColors = ['Red','Green','Blue','Yellow','Magenta','Maroon','Umbra','Turquoise']; + vm.availableColors = ['Red','Green','Blue','Yellow','Magenta','Maroon','Umbra','Turquoise']; - $scope.singleDemo = {}; - $scope.singleDemo.color = ''; - $scope.multipleDemo = {}; - $scope.multipleDemo.colors = ['Blue','Red']; - $scope.multipleDemo.colors2 = ['Blue','Red']; - $scope.multipleDemo.selectedPeople = [$scope.people[5], $scope.people[4]]; - $scope.multipleDemo.selectedPeople2 = $scope.multipleDemo.selectedPeople; - $scope.multipleDemo.selectedPeopleWithGroupBy = [$scope.people[8], $scope.people[6]]; - $scope.multipleDemo.selectedPeopleSimple = ['samantha@email.com','wladimir@email.com']; + vm.singleDemo = {}; + vm.singleDemo.color = ''; + vm.multipleDemo = {}; + vm.multipleDemo.colors = ['Blue','Red']; + vm.multipleDemo.colors2 = ['Blue','Red']; + vm.multipleDemo.selectedPeople = [vm.people[5], vm.people[4]]; + vm.multipleDemo.selectedPeople2 = vm.multipleDemo.selectedPeople; + vm.multipleDemo.selectedPeopleWithGroupBy = [vm.people[8], vm.people[6]]; + vm.multipleDemo.selectedPeopleSimple = ['samantha@email.com','wladimir@email.com']; - $scope.appendToBodyDemo = { + vm.appendToBodyDemo = { remainingToggleTime: 0, present: true, startToggleTimer: function() { - var scope = $scope.appendToBodyDemo; + var scope = vm.appendToBodyDemo; var promise = $interval(function() { if (scope.remainingTime < 1000) { $interval.cancel(promise); @@ -192,26 +194,26 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) { } }; - $scope.address = {}; - $scope.refreshAddresses = function(address) { + vm.address = {}; + vm.refreshAddresses = function(address) { var params = {address: address, sensor: false}; return $http.get( 'http://maps.googleapis.com/maps/api/geocode/json', {params: params} ).then(function(response) { - $scope.addresses = response.data.results; + vm.addresses = response.data.results; }); }; - $scope.addPerson = function(item, model){ + vm.addPerson = function(item, model){ if(item.hasOwnProperty('isTag')) { delete item.isTag; - $scope.people.push(item); + vm.people.push(item); } } - $scope.country = {}; - $scope.countries = [ // Taken from https://gist.github.com/unceus/6501985 + vm.country = {}; + vm.countries = [ // Taken from https://gist.github.com/unceus/6501985 {name: 'Afghanistan', code: 'AF'}, {name: 'Åland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'}, diff --git a/docs/assets/docs.css b/docs/assets/docs.css new file mode 100644 index 000000000..98ed6173e --- /dev/null +++ b/docs/assets/docs.css @@ -0,0 +1,339 @@ +/* + Taken from angular-ui/bootstrap + See https://github.com/angular-ui/bootstrap/blob/master/misc/demo/assets/demo.css +*/ + +body { + opacity: 1; + -webkit-transition: opacity 1s ease; + -moz-transition: opacity 1s ease; + transition: opacity 1s; +} + +.ng-cloak { + opacity: 0; +} + +.ng-invalid { + border: 1px solid red !important; +} + +section { + padding-top: 30px; +} + +.page-header h1 > small > a { + color: #999; +} + + .page-header h1 > small > a:hover { + text-decoration: none; + } + +.footer { + text-align: center; + padding: 30px 0; + margin-top: 70px; + border-top: 1px solid #e5e5e5; + background-color: #f5f5f5; +} + +.bs-social { + margin-top: 20px; + margin-bottom: 20px; + text-align: center; +} + +@media (min-width: 768px) { + + .bs-social { + text-align: left; + } +} + +.nav, .pagination, .carousel, .panel-title a { + cursor: pointer; +} + +.bs-social-buttons { + display: inline-block; + margin-bottom: 0; + padding-left: 0; + list-style: none; +} + + .bs-social-buttons li { + display: inline-block; + padding: 5px 8px; + line-height: 1; + } + +@media (max-width: 767px) { + + .visible-xs.collapse.in { + display: block !important; + } + + .visible-xs.collapse { + display: none !important; + } +} + +.navbar .collapse { + border-top: 1px solid #e7e7e7; + margin-left: -15px; + margin-right: -15px; + padding-right: 15px; + padding-left: 15px; +} + +.show-grid { + margin-bottom: 15px; +} + +/* + * Container + * + * Tweak to width of container. + */ + +/*@media (min-width: 1200px) { + .container{ + max-width: 970px; + } +}*/ + +/* + * Tabs + * + * Tweaks to the Tabs. + */ + +.code .nav-tabs { + border-bottom: 1px solid #ccc; +} + +.code pre, .code code { + border-top: none; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.code .nav-tabs > li.active > a, .code .nav-tabs > li.active > a:hover, .code .nav-tabs > li.active > a:focus { + background-color: #f8f8f8; + border: 1px solid #ccc; + border-bottom-color: transparent; +} + +/* + * Button Inverse + * + * Buttons in the masthead. + */ + +.btn-outline-inverse { + color: #fff; + background-color: transparent; + border-color: #cdbfe3; + margin: 10px; +} + +@media (min-width: 768px) { + + .btn-outline-inverse { + width: auto; + margin: 20px 5px 20px 0; + padding: 18px 24px; + font-size: 21px; + } +} + +.btn-outline-inverse:hover, .btn-outline-inverse:focus, .btn-outline-inverse:active { + color: #563d7c; + text-shadow: none; + background-color: #fff; + border-color: #fff; +} + + +/* Page headers */ +.bs-header { + padding: 30px 15px 40px; /* side padding builds on .container 15px, so 30px */ + font-size: 16px; + text-align: center; + text-shadow: 0 1px 0 rgba(0,0,0,.15); + color: #cdbfe3; + background-color: #563d7c; + background-image: url(header.png); +} + + .bs-header a { + color: #fff; + font-weight: normal; + } + + .bs-header h1 { + color: #fff; + } + + .bs-header p { + font-weight: 200; + line-height: 1.4; + } + + .bs-header .container { + position: relative; + } + +@media (min-width: 768px) { + .bs-header { + font-size: 30px; + text-align: left; + } + + .bs-header h1 { + font-size: 100px; + line-height: 1; + } +} + +@media (min-width: 992px) { + .bs-header p { + margin-right: 25%; + } +} + +.navbar-inner { + -webkit-box-shadow: 0 3px 3px rgba(0,0,0,0.175); + box-shadow: 0 3px 3px rgba(0,0,0,0.175); +} + +/* + * Side navigation + * + * Scrollspy and affixed enhanced navigation to highlight sections and secondary + * sections of docs content. + */ + +/* By default it's not affixed in mobile views, so undo that */ +.bs-sidebar.affix { + position: static; +} + +/* First level of nav */ +.bs-sidenav { + margin-top: 30px; + margin-bottom: 30px; + padding-top: 10px; + padding-bottom: 10px; + text-shadow: 0 1px 0 #fff; + background-color: #f7f5fa; + border-radius: 5px; +} + +/* All levels of nav */ +.bs-sidebar .nav > li > a { + display: block; + color: #716b7a; + padding: 5px 20px; +} + + .bs-sidebar .nav > li > a:hover, + .bs-sidebar .nav > li > a:focus { + text-decoration: none; + background-color: #e5e3e9; + border-right: 1px solid #dbd8e0; + } + +.bs-sidebar .nav > .active > a, +.bs-sidebar .nav > .active:hover > a, +.bs-sidebar .nav > .active:focus > a { + font-weight: bold; + color: #563d7c; + background-color: transparent; + border-right: 1px solid #563d7c; +} + +/* Nav: second level (shown on .active) */ +.bs-sidebar .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + margin-bottom: 8px; +} + + .bs-sidebar .nav .nav > li > a { + padding-top: 3px; + padding-bottom: 3px; + padding-left: 30px; + font-size: 90%; + } + +/* Show and affix the side nav when space allows it */ +@media (min-width: 992px) { + .bs-sidebar .nav > .active > ul { + display: block; + } + /* Widen the fixed sidebar */ + .bs-sidebar.affix, + .bs-sidebar.affix-bottom { + width: 213px; + } + + .bs-sidebar.affix { + position: fixed; /* Undo the static from mobile first approach */ + top: 80px; + } + + .bs-sidebar.affix-bottom { + position: absolute; /* Undo the static from mobile first approach */ + } + + .bs-sidebar.affix-bottom .bs-sidenav, + .bs-sidebar.affix .bs-sidenav { + margin-top: 0; + margin-bottom: 0; + } +} + +@media (min-width: 1200px) { + /* Widen the fixed sidebar again */ + .bs-sidebar.affix-bottom, + .bs-sidebar.affix { + width: 263px; + } +} + + +/* Not enough room on mobile for markup tab, js tab, and plunk btn. + And no one cares about plunk button on a phone anyway */ +@media only screen and (max-device-width: 480px) { + #plunk-btn { + display: none; + } +} + +.navbar-nav .dropdown .navbar-brand { + max-width: 100%; + margin-right: inherit; + margin-left: inherit; +} + +.header-placeholder { + height: 50px; +} + +@media screen and (min-width: 768px) { + + .dropdown.open > .navbar-brand + .dropdown-menu { + left: 10px; + } + + .header-placeholder { + height: 50px; + } + + .navbar-nav .dropdown .navbar-brand { + max-width: 200px; + margin-right: 5px; + margin-left: 10px; + } +} diff --git a/docs/assets/plunkr.js b/docs/assets/plunkr.js new file mode 100644 index 000000000..deee25ed1 --- /dev/null +++ b/docs/assets/plunkr.js @@ -0,0 +1,110 @@ +angular.module('plunkr', []) +.factory('formPostData', ['$document', function ($document) { + return function (url, newWindow, fields) { + /** + * If the form posts to target="_blank", pop-up blockers can cause it not to work. + * If a user choses to bypass pop-up blocker one time and click the link, they will arrive at + * a new default plnkr, not a plnkr with the desired template. Given this undesired behavior, + * some may still want to open the plnk in a new window by opting-in via ctrl+click. The + * newWindow param allows for this possibility. + */ + var target = newWindow ? '_blank' : '_self'; + var form = angular.element('
'); + angular.forEach(fields, function (value, name) { + var input = angular.element(''); + input.attr('value', value); + form.append(input); + }); + $document.find('body').append(form); + form[0].submit(); + form.remove(); + }; +}]) + + +.directive('plnkrOpener', ['$q', 'getExampleData', 'formPostData', function ($q, getExampleData, formPostData) { + return { + scope: {}, + bindToController: { + 'examplePath': '@' + }, + controllerAs: 'plnkr', + template: ' ', + controller: [function () { + var ctrl = this; + + ctrl.prepareExampleData = function (examplePath) { + if (ctrl.prepared) { + return $q.when(ctrl.prepared); + } else { + return getExampleData(examplePath).then(function (data) { + ctrl.prepared = data; + }); + } + }; + + ctrl.open = function (clickEvent) { + + var newWindow = clickEvent.ctrlKey || clickEvent.metaKey; + var postData = { + 'tags[0]': "angularjs", + 'tags[1]': "ui-select", + 'private': true + }; + + // Make sure the example data is available. + // If an XHR must be made, this might break some pop-up blockers when + // new window is requested + ctrl.prepareExampleData(ctrl.examplePath) + .then(function () { + angular.forEach(ctrl.prepared, function (file) { + postData['files[' + file.name + ']'] = file.content; + }); + + postData.description = "Angular ui-select http://github.com/angular-ui/ui-select/"; + + formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData); + }); + }; + + // Initialize the example data, so it's ready when clicking the open button. + // Otherwise pop-up blockers will prevent a new window from opening + ctrl.prepareExampleData(ctrl.examplePath); + }] + }; +}]) + +.factory('getExampleData', ['$http', '$q', function ($http, $q) { + return function (exampleFile) { + // Load the manifest for the example + var defaultFiles = { + 'demo.js': './assets/', + 'select.css': './dist', + 'select.js': './dist' + }; + files = angular.copy(defaultFiles); + files[exampleFile] = './'; + + var filePromises = []; + + angular.forEach(files, function (folder, filename) { + filePromises.push($http.get(folder + '/' + filename, { transformResponse: [], cache: true }) + .then(function (response) { + + var content = response.data; + // Should only be one html (the example) + if (filename.match(/.html$/)) { + filename = "index.html"; + content = content.replace(/.\/assets\//g, './').replace(/.\/dist\//g, './'); + } + + return { + name: filename, + content: content + }; + })); + }); + + return $q.all(filePromises); + }; +}]); diff --git a/docs/examples/demo-append-to-body.html b/docs/examples/demo-append-to-body.html new file mode 100644 index 000000000..a731ac2d4 --- /dev/null +++ b/docs/examples/demo-append-to-body.html @@ -0,0 +1,56 @@ + + + + + +Selected: {{ctrl.address.selected.formatted_address}}
+The select dropdown menu should be displayed above this element.
+Selected: {{ctrl.person.selected}}
+The select dropdown menu should be displayed above this element.
+Selected: {{ctrl.country.selected}}
+The select dropdown menu should be displayed above this element.
+Selected: {{ctrl.address.selected.formatted_address}}
+Selected: {{ctrl.person.selected}}
+Selected: {{ctrl.country.selected}}
+Selected: {{ctrl.personAsync.selected | json }}
List Count: {{ (ctrl.peopleAsync || []).length }}
Data will be populated in 3 secs
diff --git a/docs/examples/demo-bind-to-single-property.html b/docs/examples/demo-bind-to-single-property.html new file mode 100644 index 000000000..9b6b92477 --- /dev/null +++ b/docs/examples/demo-bind-to-single-property.html @@ -0,0 +1,22 @@ + + + + +Selected: {{ctrl.person.selected}}
Runs ctrl.person.selected = 'wladimir@email.com'
Selected: {{person.selected.name}}
+Selected: {{ctrl.person.selected.name}}