Dart Documentationangular.core.domBlockFactory

BlockFactory class

BlockFactory is used to create new Blocks. BlockFactory is created by the Compiler as a result of compiling a template.

class BlockFactory {
 final List directivePositions;
 final List<dom.Node> templateElements;
 final Profiler _perf;


 BlockFactory(this.templateElements, this.directivePositions, this._perf);

 BoundBlockFactory bind(Injector injector) {
   return new BoundBlockFactory(this, injector);
 }

 Block call(Injector injector, [List<dom.Node> elements]) {
   if (elements == null) {
     elements = cloneElements(templateElements);
   }
   try {
     assert(_perf.startTimer('ng.block') != false);
     var block = new Block(elements);
     _link(block, elements, directivePositions, injector);
     return block;
   } finally {
     assert(_perf.stopTimer('ng.block') != false);
   }
 }

 _link(Block block, List<dom.Node> nodeList, List directivePositions, Injector parentInjector) {
   var preRenderedIndexOffset = 0;
   var directiveDefsByName = {
   };

   for (num i = 0, ii = directivePositions.length; i < ii;) {
     num index = directivePositions[i++];

     List<DirectiveRef> directiveRefs = directivePositions[i++];
     List childDirectivePositions = directivePositions[i++];
     var nodeListIndex = index + preRenderedIndexOffset;
     dom.Node node = nodeList[nodeListIndex];

     try {
       assert(_perf.startTimer('ng.block.link(${_html(node)})') != false);
       // if node isn't attached to the DOM, create a parent for it.
       var parentNode = node.parentNode;
       var fakeParent = false;
       if (parentNode == null) {
         fakeParent = true;
         parentNode = new dom.DivElement();
         parentNode.append(node);
       }

       var childInjector = _instantiateDirectives(block, parentInjector, node,
                       directiveRefs, parentInjector.get(Parser));

       if (childDirectivePositions != null) {
         _link(block, node.nodes, childDirectivePositions, childInjector);
       }

       if (fakeParent) {
         // extract the node from the parentNode.
         nodeList[nodeListIndex] = parentNode.nodes[0];
       }
     } finally {
       assert(_perf.stopTimer('ng.block.link(${_html(node)})') != false);
     }
   }
 }

 Injector _instantiateDirectives(Block block, Injector parentInjector,
                                 dom.Node node, List<DirectiveRef> directiveRefs,
                                 Parser parser) {
   assert(_perf.startTimer('ng.block.link.setUp(${_html(node)}})') != false);
   Injector nodeInjector;
   Scope scope;
   Map<Type, _ComponentFactory> fctrs;
   var nodeAttrs = node is dom.Element ? new NodeAttrs(node) : null;

   try {
     if (directiveRefs == null || directiveRefs.length == 0) return parentInjector;
     var nodeModule = new Module();
     var blockHoleFactory = (_) => null;
     var blockFactory = (_) => null;
     var boundBlockFactory = (_) => null;
     var nodesAttrsDirectives = null;

     nodeModule.value(Block, block);
     nodeModule.value(dom.Element, node);
     nodeModule.value(dom.Node, node);
     nodeModule.value(NodeAttrs, nodeAttrs);
     directiveRefs.forEach((DirectiveRef ref) {
       NgAnnotation annotation = ref.annotation;
       var visibility = _elementOnly;
       if (ref.annotation.visibility == NgDirective.CHILDREN_VISIBILITY) {
         visibility = null;
       } else if (ref.annotation.visibility == NgDirective.DIRECT_CHILDREN_VISIBILITY) {
         visibility = _elementDirectChildren;
       }
       if (ref.type == NgTextMustacheDirective) {
         nodeModule.factory(NgTextMustacheDirective, (Injector injector) {
           return new NgTextMustacheDirective(
               node, ref.value, injector.get(Interpolate), injector.get(Scope),
               injector.get(TextChangeListener));
         });
       } else if (ref.type == NgAttrMustacheDirective) {
         if (nodesAttrsDirectives == null) {
           nodesAttrsDirectives = [];
           nodeModule.factory(NgAttrMustacheDirective, (Injector injector) {
             var scope = injector.get(Scope);
             var interpolate = injector.get(Interpolate);
             for(var ref in nodesAttrsDirectives) {
               new NgAttrMustacheDirective(nodeAttrs, ref.value, interpolate, scope);
             }
           });
         }
         nodesAttrsDirectives.add(ref);
       } else if (ref.annotation is NgComponent) {
         //nodeModule.factory(type, new ComponentFactory(node, ref.directive), visibility: visibility);
         // TODO(misko): there should be no need to wrap function like this.
         nodeModule.factory(ref.type, (Injector injector) {
           Compiler compiler = injector.get(Compiler);
           Scope scope = injector.get(Scope);
           BlockCache blockCache = injector.get(BlockCache);
           Http http = injector.get(Http);
           TemplateCache templateCache = injector.get(TemplateCache);
           // This is a bit of a hack since we are returning different type then we are.
           var componentFactory = new _ComponentFactory(node, ref.type, ref.annotation as NgComponent, injector.get(dom.NodeTreeSanitizer));
           if (fctrs == null) fctrs = new Map<Type, _ComponentFactory>();
           fctrs[ref.type] = componentFactory;
           return componentFactory.call(injector, compiler, scope, blockCache, http, templateCache);
         }, visibility: visibility);
       } else {
         nodeModule.type(ref.type, visibility: visibility);
       }
       for (var publishType in ref.annotation.publishTypes) {
         nodeModule.factory(publishType, (Injector injector) => injector.get(ref.type), visibility: visibility);
       }
       if (annotation.children == NgAnnotation.TRANSCLUDE_CHILDREN) {
         // Currently, transclude is only supported for NgDirective.
         assert(annotation is NgDirective);
         blockHoleFactory = (_) => new BlockHole([node]);
         blockFactory = (_) => ref.blockFactory;
         boundBlockFactory = (Injector injector) => ref.blockFactory.bind(injector);
       }
     });
     nodeModule.factory(BlockHole, blockHoleFactory);
     nodeModule.factory(BlockFactory, blockFactory);
     nodeModule.factory(BoundBlockFactory, boundBlockFactory);
     nodeInjector = parentInjector.createChild([nodeModule]);
     scope = nodeInjector.get(Scope);
   } finally {
     assert(_perf.stopTimer('ng.block.link.setUp(${_html(node)}})') != false);
   }
   directiveRefs.forEach((DirectiveRef ref) {
     try {
       assert(_perf.startTimer('ng.block.link.${ref.type}') != false);
       var controller = nodeInjector.get(ref.type);
       assert(_perf.startTimer('ng.block.link.${ref.type}.map') != false);
       var shadowScope = (fctrs != null && fctrs.containsKey(ref.type)) ? fctrs[ref.type].shadowScope : null;
       if (ref.annotation.publishAs != null) {
         (shadowScope == null ? scope : shadowScope)[ref.annotation.publishAs] = controller;
       }
       if (nodeAttrs == null) nodeAttrs = new _AnchorAttrs(ref);
       for(var map in ref.mappings) {
         map(nodeAttrs, scope, controller);
       }
       if (controller is NgAttachAware) {
         var removeWatcher;
         removeWatcher = scope.$watch(() {
           removeWatcher();
           controller.attach();
         });
       }
       if (controller is NgDetachAware) {
         scope.$on(r'$destroy', controller.detach);
       }
       assert(_perf.stopTimer('ng.block.link.${ref.type}.map') != false);
     } finally {
       assert(_perf.stopTimer('ng.block.link.${ref.type}') != false);
     }
   });
   return nodeInjector;
 }

 // DI visibility callback allowing node-local visibility.

 static final Function _elementOnly = (Injector requesting, Injector defining) {
   if (requesting.name == _SHADOW) {
     requesting = requesting.parent;
   }
   return identical(requesting, defining);
 };

 // DI visibility callback allowing visibility from direct child into parent.

 static final Function _elementDirectChildren = (Injector requesting, Injector defining) {
   if (requesting.name == _SHADOW) {
     requesting = requesting.parent;
   }
   return _elementOnly(requesting, defining) || identical(requesting.parent, defining);
 };
}

Constructors

new BlockFactory(List<Node> templateElements, List directivePositions, Profiler _perf) #

Creates a new Object instance.

Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.

docs inherited from Object
BlockFactory(this.templateElements, this.directivePositions, this._perf);

Properties

final List directivePositions #

final List directivePositions

final List<Node> templateElements #

final List<dom.Node> templateElements

Methods

BoundBlockFactory bind(Injector injector) #

BoundBlockFactory bind(Injector injector) {
 return new BoundBlockFactory(this, injector);
}

Block call(Injector injector, [List<Node> elements]) #

Block call(Injector injector, [List<dom.Node> elements]) {
 if (elements == null) {
   elements = cloneElements(templateElements);
 }
 try {
   assert(_perf.startTimer('ng.block') != false);
   var block = new Block(elements);
   _link(block, elements, directivePositions, injector);
   return block;
 } finally {
   assert(_perf.stopTimer('ng.block') != false);
 }
}