Commit 43306c3a authored by Addy Osmani's avatar Addy Osmani Committed by Sam Saccone

Drops the Angular performance example (#1586)

* learn.json: drop angularjs-perf

* index.html: drop angularjs-perf listing

* examples: drop AngularJS perf example as requested
parent 2909d17d
node_modules/todomvc-common
!node_modules/todomvc-common/base.js
!node_modules/todomvc-common/base.css
node_modules/todomvc-app-css
!node_modules/todomvc-app-css/index.css
node_modules/angular
!node_modules/angular/angular.js
<!doctype html>
<html lang="en" ng-app="todomvc" data-framework="angularjs">
<head>
<meta charset="utf-8">
<title>AngularJS • TodoMVC</title>
<link rel="stylesheet" href="node_modules/todomvc-common/base.css">
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
<style>[ng-cloak] { display: none; }</style>
</head>
<body>
<section id="todoapp" ng-controller="TodoCtrl as TC">
<header id="header">
<h1>todos</h1>
<form id="todo-form" ng-submit="TC.addTodo()">
<input id="new-todo" placeholder="What needs to be done?" ng-model="TC.newTodo.title" autofocus>
</form>
</header>
<section id="main" ng-show="TC.todos.length" ng-cloak>
<input id="toggle-all" type="checkbox" ng-model="TC.allChecked" ng-click="TC.markAll(TC.allChecked)">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
<li ng-repeat="todo in TC.todos | filter:TC.statusFilter track by $index"
ng-class="{completed: todo.completed, editing: todo === TC.editedTodo}">
<div class="view">
<input class="toggle" type="checkbox" ng-model="todo.completed">
<label ng-dblclick="TC.editTodo(todo)">{{todo.title}}</label>
<button class="destroy" ng-click="TC.removeTodo($index)"></button>
</div>
<form ng-submit="TC.doneEditing(todo, $index)">
<input class="edit"
ng-trim="false"
ng-model="todo.title"
ng-blur="TC.doneEditing(todo, $index)"
ng-keydown="($event.keyCode === TC.ESCAPE_KEY) && TC.revertEditing($index)"
todo-focus="todo === TC.editedTodo">
</form>
</li>
</ul>
</section>
<footer id="footer" ng-show="TC.todos.length" ng-cloak>
<span id="todo-count"><strong>{{TC.remainingCount}}</strong>
<ng-pluralize count="TC.remainingCount" when="{ one: 'item left', other: 'items left' }"></ng-pluralize>
</span>
<ul id="filters">
<li>
<a ng-class="{selected: TC.location.path() == '/'} " href="#/">All</a>
</li>
<li>
<a ng-class="{selected: TC.location.path() == '/active'}" href="#/active">Active</a>
</li>
<li>
<a ng-class="{selected: TC.location.path() == '/completed'}" href="#/completed">Completed</a>
</li>
</ul>
<button id="clear-completed" ng-click="TC.clearCompletedTodos()" ng-show="TC.remainingCount < TC.todos.length">Clear completed</button>
</footer>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Credits:
<a href="http://twitter.com/cburgdorf">Christoph Burgdorf</a>,
<a href="http://ericbidelman.com">Eric Bidelman</a>,
<a href="http://jacobmumm.com">Jacob Mumm</a> and
<a href="http://blog.igorminar.com">Igor Minar</a>
</p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<script src="node_modules/todomvc-common/base.js"></script>
<script src="node_modules/angular/angular.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/todoCtrl.js"></script>
<script src="js/services/todoStorage.js"></script>
<script src="js/directives/todoFocus.js"></script>
</body>
</html>
/* jshint undef: true, unused: true */
/*global angular */
(function () {
'use strict';
/**
* The main TodoMVC app module that pulls all dependency modules declared in same named files
*
* @type {angular.Module}
*/
angular.module('todomvc', ['todoCtrl', 'todoFocus', 'todoStorage']);
})();
/* jshint undef: true, unused: true */
/*global angular */
/*
* Line below lets us save `this` as `TC`
* to make properties look exactly the same as in the template
*/
//jscs:disable safeContextKeyword
(function () {
'use strict';
angular.module('todoCtrl', [])
/**
* The main controller for the app. The controller:
* - retrieves and persists the model via the todoStorage service
* - exposes the model to the template and provides event handlers
*/
.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage) {
var TC = this;
var todos = TC.todos = todoStorage.get();
TC.ESCAPE_KEY = 27;
TC.editedTodo = {};
function resetTodo() {
TC.newTodo = {title: '', completed: false};
}
resetTodo();
if ($location.path() === '') {
$location.path('/');
}
TC.location = $location;
$scope.$watch('TC.location.path()', function (path) {
TC.statusFilter = { '/active': {completed: false}, '/completed': {completed: true} }[path];
});
// 3rd argument `true` for deep object watching
$scope.$watch('TC.todos', function () {
TC.remainingCount = todos.filter(function (todo) { return !todo.completed; }).length;
TC.allChecked = (TC.remainingCount === 0);
// Save any changes to localStorage
todoStorage.put(todos);
}, true);
TC.addTodo = function () {
var newTitle = TC.newTodo.title = TC.newTodo.title.trim();
if (newTitle.length === 0) {
return;
}
todos.push(TC.newTodo);
resetTodo();
};
TC.editTodo = function (todo) {
TC.editedTodo = todo;
// Clone the original todo to restore it on demand.
TC.originalTodo = angular.copy(todo);
};
TC.doneEditing = function (todo, index) {
TC.editedTodo = {};
todo.title = todo.title.trim();
if (!todo.title) {
TC.removeTodo(index);
}
};
TC.revertEditing = function (index) {
TC.editedTodo = {};
todos[index] = TC.originalTodo;
};
TC.removeTodo = function (index) {
todos.splice(index, 1);
};
TC.clearCompletedTodos = function () {
TC.todos = todos = todos.filter(function (val) {
return !val.completed;
});
};
TC.markAll = function (completed) {
todos.forEach(function (todo) {
todo.completed = completed;
});
};
});
})();
//jscs:enable
/* jshint undef: true, unused: true */
/*global angular */
(function () {
'use strict';
angular.module('todoFocus', [])
/**
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true
*/
.directive('todoFocus', function ($timeout) {
return function (scope, elem, attrs) {
scope.$watch(attrs.todoFocus, function (newVal) {
if (newVal) {
$timeout(function () {
elem[0].focus();
}, 0, false);
}
});
};
});
})();
/* jshint undef: true, unused: true */
/*global angular */
(function () {
'use strict';
angular.module('todoStorage', [])
/**
* Services that persists and retrieves TODOs from localStorage
*/
.factory('todoStorage', function () {
var STORAGE_ID = 'todos-angularjs-perf';
return {
get: function () {
return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
},
put: function (todos) {
localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
}
};
});
})();
This source diff could not be displayed because it is too large. You can view the blob instead.
html,
body {
margin: 0;
padding: 0;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
font-weight: 300;
}
button,
input[type="checkbox"] {
outline: none;
}
.hidden {
display: none;
}
#todoapp {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp h1 {
position: absolute;
top: -155px;
width: 100%;
font-size: 100px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
#new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
}
#main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
label[for='toggle-all'] {
display: none;
}
#toggle-all {
position: absolute;
top: -55px;
left: -12px;
width: 60px;
height: 34px;
text-align: center;
border: none; /* Mobile Safari */
}
#toggle-all:before {
content: '❯';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
#toggle-all:checked:before {
color: #737373;
}
#todo-list {
margin: 0;
padding: 0;
list-style: none;
}
#todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.editing {
border-bottom: none;
padding: 0;
}
#todo-list li.editing .edit {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
margin: 0 0 0 43px;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
#todo-list li .toggle:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
}
#todo-list li .toggle:checked:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
}
#todo-list li label {
white-space: pre-line;
word-break: break-all;
padding: 15px 60px 15px 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
#todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
#todo-list li .destroy:hover {
color: #af5b5e;
}
#todo-list li .destroy:after {
content: '×';
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list li .edit {
display: none;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#footer {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
#footer:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2),
0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
#todo-count {
float: left;
text-align: left;
}
#todo-count strong {
font-weight: 300;
}
#filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
#filters li {
display: inline;
}
#filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
#filters li a.selected,
#filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
#filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
#clear-completed,
html #clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
position: relative;
}
#clear-completed:hover {
text-decoration: underline;
}
#info {
margin: 65px auto 0;
color: #bfbfbf;
font-size: 10px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
#info p {
line-height: 1;
}
#info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
#info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
#toggle-all,
#todo-list li .toggle {
background: none;
}
#todo-list li .toggle {
height: 40px;
}
#toggle-all {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
@media (max-width: 430px) {
#footer {
height: 50px;
}
#filters {
bottom: 10px;
}
}
hr {
margin: 20px 0;
border: 0;
border-top: 1px dashed #c5c5c5;
border-bottom: 1px dashed #f7f7f7;
}
.learn a {
font-weight: normal;
text-decoration: none;
color: #b83f45;
}
.learn a:hover {
text-decoration: underline;
color: #787e7e;
}
.learn h3,
.learn h4,
.learn h5 {
margin: 10px 0;
font-weight: 500;
line-height: 1.2;
color: #000;
}
.learn h3 {
font-size: 24px;
}
.learn h4 {
font-size: 18px;
}
.learn h5 {
margin-bottom: 0;
font-size: 14px;
}
.learn ul {
padding: 0;
margin: 0 0 30px 25px;
}
.learn li {
line-height: 20px;
}
.learn p {
font-size: 15px;
font-weight: 300;
line-height: 1.3;
margin-top: 0;
margin-bottom: 0;
}
#issue-count {
display: none;
}
.quote {
border: none;
margin: 20px 0 60px 0;
}
.quote p {
font-style: italic;
}
.quote p:before {
content: '“';
font-size: 50px;
opacity: .15;
position: absolute;
top: -20px;
left: 3px;
}
.quote p:after {
content: '”';
font-size: 50px;
opacity: .15;
position: absolute;
bottom: -42px;
right: 3px;
}
.quote footer {
position: absolute;
bottom: -40px;
right: 0;
}
.quote footer img {
border-radius: 3px;
}
.quote footer a {
margin-left: 5px;
vertical-align: middle;
}
.speech-bubble {
position: relative;
padding: 10px;
background: rgba(0, 0, 0, .04);
border-radius: 5px;
}
.speech-bubble:after {
content: '';
position: absolute;
top: 100%;
right: 30px;
border: 13px solid transparent;
border-top-color: rgba(0, 0, 0, .04);
}
.learn-bar > .learn {
position: absolute;
width: 272px;
top: 8px;
left: -300px;
padding: 10px;
border-radius: 5px;
background-color: rgba(255, 255, 255, .6);
transition-property: left;
transition-duration: 500ms;
}
@media (min-width: 899px) {
.learn-bar {
width: auto;
padding-left: 300px;
}
.learn-bar > .learn {
left: 8px;
}
}
/* global _ */
(function () {
'use strict';
/* jshint ignore:start */
// Underscore's Template Module
// Courtesy of underscorejs.org
var _ = (function (_) {
_.defaults = function (object) {
if (!object) {
return object;
}
for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
var iterable = arguments[argsIndex];
if (iterable) {
for (var key in iterable) {
if (object[key] == null) {
object[key] = iterable[key];
}
}
}
}
return object;
}
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a
// string literal.
var escapes = {
"'": "'",
'\\': '\\',
'\r': 'r',
'\n': 'n',
'\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
_.template = function(text, data, settings) {
var render;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
var matcher = new RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// Compile the template source, escaping string literals appropriately.
var index = 0;
var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
source += text.slice(index, offset)
.replace(escaper, function(match) { return '\\' + escapes[match]; });
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
}
if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
}
if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
index = offset + match.length;
return match;
});
source += "';\n";
// If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
source + "return __p;\n";
try {
render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
if (data) return render(data, _);
var template = function(data) {
return render.call(this, data, _);
};
// Provide the compiled function source as a convenience for precompilation.
template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
return template;
};
return _;
})({});
if (location.hostname === 'todomvc.com') {
window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
}
/* jshint ignore:end */
function redirect() {
if (location.hostname === 'tastejs.github.io') {
location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
}
}
function findRoot() {
var base = location.href.indexOf('examples/');
return location.href.substr(0, base);
}
function getFile(file, callback) {
if (!location.host) {
return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
}
var xhr = new XMLHttpRequest();
xhr.open('GET', findRoot() + file, true);
xhr.send();
xhr.onload = function () {
if (xhr.status === 200 && callback) {
callback(xhr.responseText);
}
};
}
function Learn(learnJSON, config) {
if (!(this instanceof Learn)) {
return new Learn(learnJSON, config);
}
var template, framework;
if (typeof learnJSON !== 'object') {
try {
learnJSON = JSON.parse(learnJSON);
} catch (e) {
return;
}
}
if (config) {
template = config.template;
framework = config.framework;
}
if (!template && learnJSON.templates) {
template = learnJSON.templates.todomvc;
}
if (!framework && document.querySelector('[data-framework]')) {
framework = document.querySelector('[data-framework]').dataset.framework;
}
this.template = template;
if (learnJSON.backend) {
this.frameworkJSON = learnJSON.backend;
this.frameworkJSON.issueLabel = framework;
this.append({
backend: true
});
} else if (learnJSON[framework]) {
this.frameworkJSON = learnJSON[framework];
this.frameworkJSON.issueLabel = framework;
this.append();
}
this.fetchIssueCount();
}
Learn.prototype.append = function (opts) {
var aside = document.createElement('aside');
aside.innerHTML = _.template(this.template, this.frameworkJSON);
aside.className = 'learn';
if (opts && opts.backend) {
// Remove demo link
var sourceLinks = aside.querySelector('.source-links');
var heading = sourceLinks.firstElementChild;
var sourceLink = sourceLinks.lastElementChild;
// Correct link path
var href = sourceLink.getAttribute('href');
sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http')));
sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML;
} else {
// Localize demo links
var demoLinks = aside.querySelectorAll('.demo-link');
Array.prototype.forEach.call(demoLinks, function (demoLink) {
if (demoLink.getAttribute('href').substr(0, 4) !== 'http') {
demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
}
});
}
document.body.className = (document.body.className + ' learn-bar').trim();
document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
};
Learn.prototype.fetchIssueCount = function () {
var issueLink = document.getElementById('issue-count-link');
if (issueLink) {
var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
var parsedResponse = JSON.parse(e.target.responseText);
if (parsedResponse instanceof Array) {
var count = parsedResponse.length
if (count !== 0) {
issueLink.innerHTML = 'This app has ' + count + ' open issues';
document.getElementById('issue-count').style.display = 'inline';
}
}
};
xhr.send();
}
};
redirect();
getFile('learn.json', Learn);
})();
{
"private": true,
"dependencies": {
"angular": "1.3.8",
"todomvc-common": "^1.0.1",
"todomvc-app-css": "^1.0.1"
}
}
# AngularJS (Performance Optimized) TodoMVC Example
> HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop.
> _[AngularJS - angularjs.org](http://angularjs.org)_
## Learning AngularJS
The [AngularJS website](http://angularjs.org) is a great resource for getting started.
Here are some links you may find helpful:
* [Tutorial](http://docs.angularjs.org/tutorial)
* [API Reference](http://docs.angularjs.org/api)
* [Developer Guide](http://docs.angularjs.org/guide)
* [Applications built with AngularJS](https://www.madewithangular.com/)
* [Blog](http://blog.angularjs.org)
* [FAQ](http://docs.angularjs.org/misc/faq)
* [AngularJS Meetups](http://www.youtube.com/angularjs)
Articles and guides from the community:
* [Code School AngularJS course](https://www.codeschool.com/courses/shaping-up-with-angular-js)
* [5 Awesome AngularJS Features](http://net.tutsplus.com/tutorials/javascript-ajax/5-awesome-angularjs-features)
* [Using Yeoman with AngularJS](http://briantford.com/blog/angular-yeoman.html)
* [me&ngular - an introduction to MVW](http://stephenplusplus.github.io/meangular)
Get help from other AngularJS users:
* [Walkthroughs and Tutorials on YouTube](http://www.youtube.com/playlist?list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz)
* [Google Groups mailing list](https://groups.google.com/forum/?fromgroups#!forum/angular)
* [angularjs on Stack Overflow](http://stackoverflow.com/questions/tagged/angularjs)
* [AngularJS on Twitter](https://twitter.com/angularjs)
* [AngularjS on Google +](https://plus.google.com/+AngularJS/posts)
_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
## Implementation
The normal AngularJS TodoMVC implementation performs deep watching of the todos array object. This means that it keeps an in-memory copy of the complete array that is used for dirty checking in order to detect model mutations. For smaller applications such as TodoMVC, this is completely fine as one trades off a little memory and performance for the sake of simplicity.
In larger more complex applications however, where one might be working with 100s or 1000s of large objects one definitely should avoid using this approach. This implementation of the AngularJS app demonstrates the correct way to approach this problem when working in larger apps.
...@@ -254,9 +254,6 @@ ...@@ -254,9 +254,6 @@
<li class="routing"> <li class="routing">
<a href="examples/enyo_backbone/" data-source="http://enyojs.com/" data-content="Enyo is a simple but powerful encapsulation model, which helps you factor application functionality into self-contained building blocks that are easy to reuse and maintain.">Enyo +<br>Backbone.js</a> <a href="examples/enyo_backbone/" data-source="http://enyojs.com/" data-content="Enyo is a simple but powerful encapsulation model, which helps you factor application functionality into self-contained building blocks that are easy to reuse and maintain.">Enyo +<br>Backbone.js</a>
</li> </li>
<li class="routing">
<a href="examples/angularjs-perf/" data-source="http://angularjs.org" data-content="What HTML would have been had it been designed for web apps. A version with several performance optimizations.">AngularJS <br>(optimized)</a>
</li>
<li class="routing"> <li class="routing">
<a href="examples/sapui5/" data-source="http://scn.sap.com/community/developer-center/front-end" data-content="SAPUI5 is SAP's HTML5-based UI technology that allows you to build rich, interactive Web applications.">SAPUI5</a> <a href="examples/sapui5/" data-source="http://scn.sap.com/community/developer-center/front-end" data-content="SAPUI5 is SAP's HTML5-based UI technology that allows you to build rich, interactive Web applications.">SAPUI5</a>
</li> </li>
......
{ {
"angularjs": { "angularjs": {
"name": "AngularJS", "name": "AngularJS",
"description": "HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop.", "description": "HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop.",
...@@ -9,9 +9,6 @@ ...@@ -9,9 +9,6 @@
}, { }, {
"name": "Require.js & AngularJS", "name": "Require.js & AngularJS",
"url": "examples/angularjs_require" "url": "examples/angularjs_require"
}, {
"name": "AngularJS Optimized",
"url": "examples/angularjs-perf"
}, { }, {
"name": "TypeScript & AngularJS", "name": "TypeScript & AngularJS",
"url": "examples/typescript-angular" "url": "examples/typescript-angular"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment