3

In the Creating Container Components...with Angular talk at the ng-conf 2015. The reference some transclusion and custom code to 'match' and 'insert' user content into specific/deliberate elements/tags of the directive's template. ie. <nav t-id="menu"></nav><main t-id="body"></main> Here is the link to the talk at the spot where they show the code being used. Got most of it working except the expression using the find() method. Here is the code:

First the statement/expression in question var target = elem.find('[t-id="'+tId+'"]'); and then full link code below.

.directive('my-container-directive', function() {
  return {
    transclude: true,
    template: `...`,
    link: function(scope, elem, ctrl, transclude) {
      transclude(clone) {
        angular.forEach(clone, function(cloneEl){
          // get desired target id
             tId = cloneEl.attributes["t-to"].value;
             // find the target with that ID
             var target = elem.find('[t-id="'+tId+'"]');
             // append an el to target
             target.append(cloneEl);

        })   
      }
    }
  };
});

Question 1: The use of the find() does not make sense to me and can not get it to work. What is with the [] syntax; It does not seem to follow either jqLites(angular's api docs) or jQuery docs. Angular for example says the find() 'Limited to look up by tag name'.

Full code is in thisplunk

Question 1.1: How would you find a tag with a certain attribute name and value name? ie. t-id="menu"?

scniro
  • 16,844
  • 8
  • 62
  • 106
jamie
  • 690
  • 7
  • 18

1 Answers1

4

The docs (both jQuery and Angular's jsLite) are correct in their specs. Check out the syntax for lookup by attribute selector

jQuery Attribute Equals Selector [name="value"]

Angular's jsLite implementation of .find() can only be used for tag lookup. An example would be elem.find('div'). This would return the <div> elements within elem.

Are you sure this example is not also using jQuery? Sometimes if jQuery is present on the page and we're trying to adhere to Angular's jqLite implementation, it'll no longer matter, for we can use all of jQuery's offerings though we think we are being bound to the jqLite api.

Here is a plunker demonstrating .find() using the full jQuery library

<div id="main">
    <div t-id="menu"></div>
</div>

$(function() {
    var parent = $('#main');
    var foundByAttributeLookup = parent.find('[t-id="menu"]');
    console.log(foundByAttributeLookup);
});

This works as expected

JQuery Plunker

Now lets try this with scrictly Angular and the jqLite api

<div id="main">
    <div t-id="menu"></div>
</div>

angular.element(document).ready(function () {
    var parent = angular.element(document.getElementById('main'));
    var foundByTagLookup = parent.find('div')
    var foundByAttributeLookup = parent.find('[t-id="menu"]')

    console.log(foundByTagLookup)         // ---- good
    console.log(foundByAttributeLookup)  // ---- no good
});

This clonks out when we try to .find() by attribute

Angular Plunker

Interestingly, add this to the top of the angular plunker, things work

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"</script>

Bringing in jQuery now allows are .find() function work just fine, even if we strictly crafted all our code to the jqLite api, using such practices such as angular.element() etc. It no longer matters.

So, here is a demonstration of the limitations of .find() considering both the jQuery and jqLite implementations. My suspicions are in the example you are following... jQuery is on the page


Possible Answer for 1.1

You may have to do a bit more manual coding for find what you are looking for. Here is a possible way to find your element by attribute without the full jQuery library that lines up with the above Plunker links

angular.element(document).ready(function () {
    var parent = angular.element(document.getElementById('main'));
    angular.forEach(parent.children(), function(value) {
        if(angular.element(value).attr('t-id') === 'menu') {
            console.log('found');
            console.log(value)
        }
    });
});

Plunker

scniro
  • 16,844
  • 8
  • 62
  • 106
  • 1. so bottom line they had to be using jquery? Thought they frown on that in angular. 2. That selector info in jQuery docs you offered. I checked the find() - how did you end up at that page if you don't mind me asking. On the surface it makes sense - but interested on how to solve my own problem nxt time. thx again – jamie Apr 02 '15 at 14:59
  • I just searched something like "jQuery find element by attribute" It's just a jQuery selector, not specific to `.find`. And yes, jQuery is on the page for this lookup by attribute, for `.find()` only allows tag lookup for jqLite in Angular world. – scniro Apr 02 '15 at 15:03