【问题标题】:Passing a binding to transcluded scope in component将绑定传递给组件中的嵌入范围
【发布时间】:2017-01-27 05:44:07
【问题描述】:

在 AngularJS 1.5 中,我想将一个组件的绑定传递到(多槽)转置范围中 - 用于模板中的引用(在一个特定的或所有的模板中 - 没有任何一种方式是好的)。

这是为了创建一个通用的自定义选择列表

// 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>

这可能来自.component()吗?带有transclusion 的自定义指令?

【问题讨论】:

  • 嵌入本质上与您想要实现的目标相反。

标签: angularjs angularjs-directive angularjs-scope web-component transclusion


【解决方案1】:

我也遇到了这个问题,在 salih 的回答的基础上,我想出了一个解决方案(免责声明 - 见底部:我认为这不一定是解决您的问题的最佳方法)。它涉及创建一个用于 mySelect 组件的存根组件,如下所示:

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

然后,调整您的模板:

<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>

这意味着总是有一个 item 组件具有绑定到它的值。现在,您可以在自定义组件中将其用作要求:

.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;
        }
    }
});

并使用它:

<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>

在我实施这个之后,我实际上决定改变我的策略;这也可能对您有用。我没有使用 transclude,而是传入了一个格式化函数,即:

.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;
            }
        }
        ..... 
    }
});

然后在模板中,只需使用:

<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>

如果您有任何反馈或问题,请告诉我!

【讨论】:

    【解决方案2】:

    在您的父组件中,my-select 保留一个变量,如“selectedItem”

    在您的子组件 my-select-item 中,要求您的父组件如下所示

    require: {
      mySelect: '^mySelect'
    }
    

    在你的 my-select-item 组件的控制器中,访问你的父组件

     $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
     }
    

    以便现在可以从以下位置访问所选项目

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

    【讨论】:

    • 是的!就是这样,我在想如何实现这一点!太糟糕了,我们不能将它挂钩到 $onChanges 生命周期事件中。尽管 $doCheck 可以为我们处理它,但感觉有点脏。
    猜你喜欢
    • 2011-06-30
    • 2018-06-26
    • 2017-08-17
    • 2016-12-03
    • 2016-07-25
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    相关资源
    最近更新 更多