diff --git a/benchmarks/largetable-bp/main.html b/benchmarks/largetable-bp/main.html index 471a4441dd9e..b4f90a4cc951 100644 --- a/benchmarks/largetable-bp/main.html +++ b/benchmarks/largetable-bp/main.html @@ -20,6 +20,7 @@
interpolation + fnInvocation:
ngBind + filter:
interpolation + filter:
+
ngModel:
@@ -84,6 +85,13 @@

interpolation with filter

{{column.i | noop}}:{{column.j | noop}}| +
+

ngModels

+
+ + +
+
diff --git a/src/ng/compile.js b/src/ng/compile.js index b1d4185f6d23..f8c7367fa3cc 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1614,7 +1614,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { var terminalPriority = -Number.MAX_VALUE, newScopeDirective, controllerDirectives = previousCompileContext.controllerDirectives, - controllers, newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, templateDirective = previousCompileContext.templateDirective, nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, @@ -1672,7 +1671,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if (!directive.templateUrl && directive.controller) { directiveValue = directive.controller; - controllerDirectives = controllerDirectives || {}; + controllerDirectives = controllerDirectives || createMap(); assertNoDuplicate("'" + directiveName + "' controller", controllerDirectives[directiveName], directive, $compileNode); controllerDirectives[directiveName] = directive; @@ -1840,49 +1839,75 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { function getControllers(directiveName, require, $element, elementControllers) { - var value, retrievalMethod = 'data', optional = false; - var $searchElement = $element; - var match; - if (isString(require)) { - match = require.match(REQUIRE_PREFIX_REGEXP); - require = require.substring(match[0].length); - - if (match[3]) { - if (match[1]) match[3] = null; - else match[1] = match[3]; - } - if (match[1] === '^') { - retrievalMethod = 'inheritedData'; - } else if (match[1] === '^^') { - retrievalMethod = 'inheritedData'; - $searchElement = $element.parent(); - } - if (match[2] === '?') { - optional = true; - } + var i, value; - value = null; + if (typeof require === 'string') { + var match = require.match(REQUIRE_PREFIX_REGEXP); + var name = require.substring(match[0].length); + var type = match[1] || match[3]; - if (elementControllers && retrievalMethod === 'data') { - if (value = elementControllers[require]) { - value = value.instance; - } + //If only parents then start at the parent element + //Otherwise attempt getting the controller from elementControllers to avoid .data + if (type === '^^') { + $element = $element.parent(); + } else { + value = elementControllers && elementControllers[name]; + value = value && value.instance; + } + + if (!value) { + var dataName = '$' + name + 'Controller'; + value = type ? $element.inheritedData(dataName) : $element.data(dataName); } - value = value || $searchElement[retrievalMethod]('$' + require + 'Controller'); - if (!value && !optional) { + if (!value && match[2] !== '?') { throw $compileMinErr('ctreq', "Controller '{0}', required by directive '{1}', can't be found!", - require, directiveName); + name, directiveName); } + return value || null; - } else if (isArray(require)) { - value = []; - forEach(require, function(require) { - value.push(getControllers(directiveName, require, $element, elementControllers)); - }); } - return value; + + if (isArray(require)) { + value = new Array(i = require.length); + while (i--) { + value[i] = getControllers(directiveName, require[i], $element, elementControllers); + } + return value; + } + } + + function setupControllers(scope, isolateScope, $element, attrs, transcludeFn, elementControllers) { + // For directives with element transclusion the element is a comment, + // but jQuery .data doesn't support attaching data to comment nodes as it's hard to + // clean up (http://bugs.jquery.com/ticket/8335). + // Instead, we save the controllers for the element in a local hash and attach to .data + // later, once we have the actual element. + var controllerData = !hasElementTranscludeDirective && $element.data(); + + for (var directiveName in controllerDirectives) { + var directive = controllerDirectives[directiveName]; + + var locals = { + $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, + $element: $element, + $attrs: attrs, + $transclude: transcludeFn + }; + + var directiveController = directive.controller; + if (directiveController === '@') { + directiveController = attrs[directive.name]; + } + + var controllerInstance = $controller(directiveController, locals, true, directive.controllerAs); + + elementControllers[directive.name] = controllerInstance; + if (controllerData) { + controllerData['$' + directive.name + 'Controller'] = controllerInstance.instance; + } + } } @@ -1911,36 +1936,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (controllerDirectives) { - // TODO: merge `controllers` and `elementControllers` into single object. - controllers = {}; - elementControllers = {}; - forEach(controllerDirectives, function(directive) { - var locals = { - $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, - $element: $element, - $attrs: attrs, - $transclude: transcludeFn - }, controllerInstance; - - controller = directive.controller; - if (controller == '@') { - controller = attrs[directive.name]; - } - - controllerInstance = $controller(controller, locals, true, directive.controllerAs); - - // For directives with element transclusion the element is a comment, - // but jQuery .data doesn't support attaching data to comment nodes as it's hard to - // clean up (http://bugs.jquery.com/ticket/8335). - // Instead, we save the controllers for the element in a local hash and attach to .data - // later, once we have the actual element. - elementControllers[directive.name] = controllerInstance; - if (!hasElementTranscludeDirective) { - $element.data('$' + directive.name + 'Controller', controllerInstance.instance); - } - - controllers[directive.name] = controllerInstance; - }); + setupControllers(scope, isolateScope, $element, attrs, transcludeFn, elementControllers = createMap()); } if (newIsolateScopeDirective) { @@ -1954,14 +1950,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { isolateScope.$$isolateBindings, newIsolateScopeDirective, isolateScope); } - if (controllers) { + if (elementControllers) { // Initialize bindToController bindings for new/isolate scopes var scopeDirective = newIsolateScopeDirective || newScopeDirective; var bindings; var controllerForBindings; - if (scopeDirective && controllers[scopeDirective.name]) { + if (scopeDirective && elementControllers[scopeDirective.name]) { bindings = scopeDirective.$$bindings.bindToController; - controller = controllers[scopeDirective.name]; + controller = elementControllers[scopeDirective.name]; if (controller && controller.identifier && bindings) { controllerForBindings = controller; @@ -1970,7 +1966,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { bindings, scopeDirective); } } - forEach(controllers, function(controller) { + // Initialize the controllers before linking + for (i in elementControllers) { + controller = elementControllers[i]; var result = controller(); if (result !== controller.instance && controller === controllerForBindings) { @@ -1980,8 +1978,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { initializeDirectiveBindings(scope, attrs, result, bindings, scopeDirective); } - }); - controllers = null; + } } // PRELINKING