diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Angular.js | 5 | ||||
| -rw-r--r-- | src/Compiler.js | 13 | ||||
| -rw-r--r-- | src/Scope.js | 27 | ||||
| -rw-r--r-- | src/directives.js | 21 | ||||
| -rw-r--r-- | src/validators.js | 2 | ||||
| -rw-r--r-- | src/widgets.js | 49 |
6 files changed, 72 insertions, 45 deletions
diff --git a/src/Angular.js b/src/Angular.js index 4d3c360f..97792868 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -53,6 +53,9 @@ function fromCharCode(code) { return String.fromCharCode(code); } var _undefined = undefined, _null = null, $$element = '$element', + $$update = '$update', + $$scope = '$scope', + $$validate = '$validate', $angular = 'angular', $array = 'array', $boolean = 'boolean', @@ -69,6 +72,8 @@ var _undefined = undefined, $number = 'number', $object = 'object', $string = 'string', + $value = 'value', + $selected = 'selected', $undefined = 'undefined', NG_EXCEPTION = 'ng-exception', NG_VALIDATION_ERROR = 'ng-validation-error', diff --git a/src/Compiler.js b/src/Compiler.js index 10d19ea8..a98bd502 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -30,6 +30,7 @@ Template.prototype = { if (this.newScope) { childScope = createScope(scope); scope.$onEval(childScope.$eval); + element.data($$scope, childScope); } foreach(this.inits, function(fn) { queue.push(function() { @@ -68,6 +69,17 @@ Template.prototype = { } }; +/* + * Function walks up the element chain looking for the scope associated with the give element. + */ +function retrieveScope(element) { + var scope; + while (element && !(scope = element.data($$scope))) { + element = element.parent(); + } + return scope; +} + /////////////////////////////////// //Compiler ////////////////////////////////// @@ -97,6 +109,7 @@ Compiler.prototype = { element = jqLite(element); var scope = parentScope && parentScope.$eval ? parentScope : createScope(parentScope); + element.data($$scope, scope); return extend(scope, { $element:element, $init: function() { diff --git a/src/Scope.js b/src/Scope.js index 09779453..203507a3 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -243,7 +243,6 @@ function createScope(parent, providers, instanceCache) { parent = Parent.prototype = (parent || {}); var instance = new Parent(); var evalLists = {sorted:[]}; - var postList = [], postHash = {}, postId = 0; extend(instance, { 'this': instance, @@ -371,11 +370,6 @@ function createScope(parent, providers, instanceCache) { instance.$tryEval(queue[j].fn, queue[j].handler); } } - while(postList.length) { - fn = postList.shift(); - delete postHash[fn.$postEvalId]; - instance.$tryEval(fn); - } } else if (type === $function) { return exp.call(instance); } else if (type === 'string') { @@ -552,27 +546,6 @@ function createScope(parent, providers, instanceCache) { /** * @workInProgress * @ngdoc function - * @name angular.scope.$postEval - * @function - */ - $postEval: function(expr) { - if (expr) { - var fn = expressionCompile(expr); - var id = fn.$postEvalId; - if (!id) { - id = '$' + instance.$id + "_" + (postId++); - fn.$postEvalId = id; - } - if (!postHash[id]) { - postList.push(postHash[id] = fn); - } - } - }, - - - /** - * @workInProgress - * @ngdoc function * @name angular.scope.$become * @function * @deprecated This method will be removed before 1.0 diff --git a/src/directives.js b/src/directives.js index 8a76f17a..d40d6120 100644 --- a/src/directives.js +++ b/src/directives.js @@ -304,7 +304,8 @@ angularDirective("ng:bind-template", function(expression, element){ var REMOVE_ATTRIBUTES = { 'disabled':'disabled', 'readonly':'readOnly', - 'checked':'checked' + 'checked':'checked', + 'selected':'selected' }; /** * @workInProgress @@ -359,27 +360,31 @@ var REMOVE_ATTRIBUTES = { angularDirective("ng:bind-attr", function(expression){ return function(element){ var lastValue = {}; - var updateFn = element.parent().data('$update'); + var updateFn = element.data($$update) || noop; this.$onEval(function(){ - var values = this.$eval(expression); + var values = this.$eval(expression), + dirty = noop; for(var key in values) { var value = compileBindTemplate(values[key]).call(this, element), specialName = REMOVE_ATTRIBUTES[lowercase(key)]; if (lastValue[key] !== value) { lastValue[key] = value; if (specialName) { - if (element[specialName] = toBoolean(value)) { - element.attr(specialName, value); + if (toBoolean(value)) { + element.attr(specialName, specialName); + element.attr('ng-' + specialName, value); } else { - element.removeAttr(key); + element.removeAttr(specialName); + element.removeAttr('ng-' + specialName); } - (element.data('$validate')||noop)(); + (element.data($$validate)||noop)(); } else { element.attr(key, value); } - this.$postEval(updateFn); + dirty = updateFn; } } + dirty(); }, element); }; }); diff --git a/src/validators.js b/src/validators.js index ea35558e..7318333a 100644 --- a/src/validators.js +++ b/src/validators.js @@ -394,7 +394,7 @@ extend(angularValidator, { element.removeClass('ng-input-indicator-wait'); scope.$invalidWidgets.markValid(element); } - element.data('$validate')(); + element.data($$validate)(); scope.$root.$eval(); }); } else if (inputState.inFlight) { diff --git a/src/widgets.js b/src/widgets.js index f34ff05c..04353bd5 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -282,7 +282,7 @@ function valueAccessor(scope, element) { required = requiredExpr === ''; } - element.data('$validate', validate); + element.data($$validate, validate); return { get: function(){ if (lastError) @@ -391,6 +391,7 @@ var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, initW // 'file': fileWidget??? }; + function initWidgetValue(initValue) { return function (model, view) { var value = view.get(); @@ -461,18 +462,13 @@ function inputWidget(events, modelAccessor, viewAccessor, initFn) { this.$eval(element.attr('ng:init')||''); // Don't register a handler if we are a button (noopAccessor) and there is no action if (action || modelAccessor !== noopAccessor) { - element.bind(events, function(event){ + element.bind(events, function (){ model.set(view.get()); lastValue = model.get(); scope.$tryEval(action, element); scope.$root.$eval(); }); } - function updateView(){ - view.set(lastValue = model.get()); - } - updateView(); - element.data('$update', updateView); scope.$watch(model.get, function(value){ if (lastValue !== value) { view.set(lastValue = value); @@ -494,15 +490,50 @@ angularWidget('select', function(element){ return inputWidgetSelector.call(this, element); }); + +/* + * Consider this: + * <select name="selection"> + * <option ng:repeat="x in [1,2]">{{x}}</option> + * </select> + * + * The issue is that the select gets evaluated before option is unrolled. + * This means that the selection is undefined, but the browser + * default behavior is to show the top selection in the list. + * To fix that we register a $update function on the select element + * and the option creation then calls the $update function when it is + * unrolled. The $update function then calls this update function, which + * then tries to determine if the model is unassigned, and if so it tries to + * chose one of the options from the list. + */ angularWidget('option', function(){ this.descend(true); this.directives(true); return function(element) { - this.$postEval(element.parent().data('$update')); + var select = element.parent(); + var scope = retrieveScope(select); + var model = modelFormattedAccessor(scope, select); + var view = valueAccessor(scope, select); + var option = element; + var lastValue = option.attr($value); + var lastSelected = option.attr('ng-' + $selected); + element.data($$update, function(){ + var value = option.attr($value); + var selected = option.attr('ng-' + $selected); + var modelValue = model.get(); + if (lastSelected != selected || lastValue != value) { + lastSelected = selected; + lastValue = value; + if (selected || modelValue == _null || modelValue == _undefined) + model.set(value); + if (value == modelValue) { + view.set(lastValue); + } + } + }); }; }); - /** * @workInProgress * @ngdoc widget |
