Passing a binding to transcluded scope in component

时光总嘲笑我的痴心妄想 提交于 2019-12-10 02:45:02

问题


In AngularJS 1.5, I want to pass a binding from a component into the (multi-slot) transcluded scope - for a reference in the template (in either one specific or all of them - no either way is fine).

This is for creating a generic custom-select list

// Component
.component('mySelect', { 
   bind: { 
       collection: '<'
   },
   transclude:{
      header: 'mySelectHeader',
      item: 'mySelectItem'
   },
   templateUrl: 'my-select-template',
   controller: function(){
       ..... 
   }
});

...
// Component template
<script id="my-select-template" type="text/ng-template">
<ol>
  <li ng-transclude="header"> </li>
  <li ng-transclude="item"
      ng-click="$ctrl.select($item)"
      ng-repeat"$item in $ctrl.collection">
  </li>
</ol>
</script>

...
// Example usage
<my-select collection="[{id: 1, name: "John"}, {id: 2, name: "Erik"}, ... ]>
   <my-select-head></my-select-head>

   <!-- Reference to $item from ng-repeate="" in component  -->
   <my-select-item>{{$item.id}}: {{$item.name}}</my-select-item>

</my-select>

Is this possible from a .component()? with custom-directives for the transclusion ?


回答1:


In your parent component my-select keep a variable like "selectedItem"

In your child component my-select-item, require your parent component like below

require: {
  mySelect: '^mySelect'
}

And in your my-select-item component's controller, to access your parent component

 $onInit = () => {
  this.mySelectedItem= this.mySelect.selectedItem; // to use it inside my-select-item component.
 };
 select($item) {
   this.mySelect.selectedItem = $item; // to change the selectedItem value stored in parent component
 }

So that the selected item is now accessible from

<my-select-item>{{selectedItem.id}}: {{selectedItem.name}}</my-select-item>



回答2:


I ran into this problem as well, and building upon salih's answer, I came up with a solution (disclaimer--see bottom: I don't think this is necessarily the best approach to your problem). it involves creating a stubbed out component for use in the mySelect component, as follows:

.component('item', {
    require: { mySelect: '^mySelect' },
    bind: { item: '<' }
})

then, tweaking your template:

<script id="my-select-template" type="text/ng-template">
<ol>
  <li ng-transclude="header"> </li>
  <li ng-click="$ctrl.select($item)"
      ng-repeat"$item in $ctrl.collection">
      <item item="$item" ng-transclude="item"></item>
  </li>
</ol>
</script>

this will mean there's always an item component with the value bound to it. now, you can use it as a require in a custom component:

.component('myItemComponent', {
    require: {
        itemCtrl: '^item',
    }
    template: '<span>{{$ctrl.item.id}}: {{$ctrl.item.name}}</span>',
    controller: function() {
        var ctrl = this;
        ctrl.$onInit = function() {
            ctrl.item = ctrl.itemCtrl.item;
        }
    }
});

and to use it:

<my-select collection="[{id: 1, name: "John"}, {id: 2, name: "Erik"}, ... ]>
   <my-select-head></my-select-head>

   <my-select-item>
       <my-item-component></my-item-component>
   </my-select-item>
</my-select>

after I implemented this, I actually decided to change my strategy; this might work for you as well. instead of using a transclude, I passed in a formatting function, i.e.:

.component('mySelect', { 
    bind: { 
        collection: '<',
        customFormat: '&?'
    },
    transclude:{
        header: 'mySelectHeader'
    },
    templateUrl: 'my-select-template',
    controller: function(){
        var ctrl = this;
        ctrl.format = function(item) {
            if(ctrl.customFormat) {
                return customFormat({item: item});
            } else {
                //default
                return item;
            }
        }
        ..... 
    }
});

then in the template, just use:

<script id="my-select-template" type="text/ng-template">
<ol>
  <li ng-transclude="header"> </li>
  <li ng-click="$ctrl.select($item)"
      ng-repeat"$item in $ctrl.collection"
      ng-bind="::$ctrl.format($item)">
  </li>
</ol>
</script>

let me know if you have any feedback or questions!



来源:https://stackoverflow.com/questions/39574792/passing-a-binding-to-transcluded-scope-in-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!