将绑定传递给组件中的嵌入范围

Posted

技术标签:

【中文标题】将绑定传递给组件中的嵌入范围【英文标题】: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 的自定义指令?

【问题讨论】:

嵌入本质上与您想要实现的目标相反。 【参考方案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 可以为我们处理它,但感觉有点脏。

以上是关于将绑定传递给组件中的嵌入范围的主要内容,如果未能解决你的问题,请参考以下文章

将范围传递给回调函数/绑定

如何在 JSF 中正确使用组件绑定? (会话范围 bean 中的请求范围组件)

将 SQL 输入日期范围传递给 SHINY 中的查询

如何将范围传递给 Google 电子表格中的自定义函数?

将范围变量从控制器绑定到指令而不使用$ watch

angularjs组件控制器未将初始绑定值传递给模板中的指令(summernote)