0

OK, I swear I've searched all over SO for answers to this. Each answer I'm finding is almost, but not quite, exactly not what I'm looking for.

Goal

I'm trying to write some directives that let me DRY up the way I display collections. Final goal is to be able to do things in the view or another directive that looks like:

<md-grid-tile index='event' index-by='isPublic' index-key='true'>
  <md-grid-tile-header>{{event.name}}</md-grid-tile-header>
  <md-grid-tile-footer>
    <profile-card index='eventOwner' index-by='event_id' index-key='event.$id' collection='profile'>
      arbitrary transcluded content that uses {{profile}}
    </profile-card>
  </md-grid-tile-footer>
</md-grid-tile>

md-grid-tile-* all come from angular-material, and do fancy transcluding things with their contents. profile-card is some arbitrary custom directive that wraps transcluded content. E.g. i have a common card to display profile info, but i want to put different action buttons on it depending on where i'm placing it.

I'm trying to create the index directive, which will act like a very focused ng-repeat. In this example:

  • The attrs on md-grid-tile element tell it to repeat over every event with an isPublic of true.
  • On the profile-card element, it will find all eventOwner objects with an event_id matching the event.$id of the containing element. It will then repeat the profile objects that those eventOwner objects reference.

Problems

I've got no problems with hooking up to the data sources, where I run into problems is:

  • Creating multiple elements in the DOM in the right place
  • Repeating elements that transclude content

For the purposes of code samples here I am simplifying the data sources. mockProvider will be replaced with a service that creates the collection based on the index-* attrs.

Attempt #1

.directive 'index', ['mockProvider', (mockProvider)->
  restrict: 'A'
  priority: 1
  compile: (el,attrs)->

    el.attr 'ng-repeat', 'item in collection'

    post: (scope,el,attrs,ctrl,transclude)->
      scope.collection = mockProvider
]

I still haven't been able to figure out why I can't get this approach to work. The ng-repeat attr gets properly attached, but nothing is repeated.

Attempt #2

.directive 'index', ['mockProvider', (mockProvider)->
  restrict: 'A'
  priority: 1 # tried with 1, 1001, -1000
  compile: (el,attrs)->
    post: (scope,el,attrs,ctrl,transclude)->
      scope.collection = mockProvider
      newEl = angular.element el[0].outerHTML
      newEl.attr 'ng-repeat', 'foo in [1,2,3]'
      newEl.removeAttr 'pb-index'
      el.replaceWith $compile(newEl[0].outerHTML)(scope)
]

This repeats a bunch of stuff, but then explodes with: [ngTransclude:orphan] Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. It seems like the re-compilation somehow loses the transcluded content? I've also seen other SO comments that warn against this due to inefficiency.

Attempt #3

.directive 'index', ['mockProvider', (mockProvider)->
  restrict: 'A'
  priority: 1001
  compile: (el,attrs)->
    post: (scope,el,attrs,ctrl,transclude)->
      el.html ""
      scope.collection = mockProvider
      scope.$watchCollection 'collection', (collection)->
        for item,index in collection
          childScope = scope.$new()
          childScope.item = item
          transclude childScope, (newElement)->
            el.append newElement

Finally, I tried a naive re-implementation of ng-repeat. This has gotten the closest, but still isn't working, and requires a bunch more code to get it to match the performance/functionality of ng-repeat.

HOW???

Am I totally on the wrong track? Is there an easy way to do this?

sdebaun
  • 43
  • 4
  • What is `pbIndex` - is this the same as `profile-chip`? I'm still confused about exactly what you are trying to achieve. Can you remove all the `md-*` stuff and services and for the purposes of the question, just simply hard-code the collections that you are referring to. You also talk about "transcluding" but nowhere do you specify `transclude: true` and you actually don't have any content under `` that you intend to transclude - so, it's hard to understand what you are getting at – New Dev Jun 03 '15 at 21:14
  • sorry for that -- i just tried to clear up a few things in the OP. `index` is the attr-based generic directive i'm trying to create. `md-grid-tile` and `profile-card` are examples of directives that use transclusion. Any directive that transcludes will serve. I know how to get the actual collection based on the `index-*` attributes. The problem is getting the `index` directive to actually repeat a transcluding element that it's attached to. – sdebaun Jun 03 '15 at 21:47
  • so what's the problem? – Connor Leech Aug 05 '15 at 03:07

0 Answers0