在指令和嵌套指令之间共享模型

时间:2013-09-23 23:06:29

标签: javascript angularjs angularjs-directive

我的应用程序中有几个项目依赖于其他项目。

示例嵌套选择:

<!-- optionsa is built from ajax -->
<select ng-model="current_optiona" ng-options="a as a.name for a in optionsa"></select>
<!-- optionsb is built when current_optiona change -->
<select ng-model="current_optionb" ng-options="b as b.name for b in optionsb"></select>
<!-- optionsc is built when current_optionb change -->
<select ng-model="current_optionc" ng-options="c as c.name for c in optionsc"></select>

问题#1 这里的问题是我必须在每个控制器中实现每个选择的方法和模型

解决方案P#1 将方法和模型移至服务

问题#2 如果我想在一个控制器上多次显示嵌套选择,所有列表(optionsa,optionsb,optionsc)都包含相同的

问题#3 并不总是相同的三个选择,可以只有两个或与其他混合

建议的解决方案构建一个指令,用于创建共享的独立模型和允许选择显示的子指令。这里的主要思想是一个指令watch和popule所有列表(optionsa,optionsb和optionsc)内部指令或只选择指令范围来获取选项,并且可以使用ng-model与控制器共享

<filters>
    <select ng-model="current_optiona" ng-options="a as a.name for a in mistery.optionsa"></select>
    <select ng-model="current_optionb" ng-options="b as b.name for b in mistery.optionsb"></select>
</filters>

问题

使用此解决方案我可以使用许多过滤器,但

  • 我如何在指令之间共享模型?
  • 我如何从指令?
  • 访问父指令模型(mistery变量)
  • 我如何从指令访问(和修改)控制器模型?

更新#1

这是一种早期的经历

directive-filter.coffee

app
.directive 'filters' , ->
  restrict: 'E'
  transclude: true
  replace: true
  scope:          # if enable the scope the
    ns: '=model'  # sub directives can access
  template: '<div ng-transclude></div>'
  controller: ($scope, MyAPI) ->
    $scope.ns =
      optionsa: []
      optionsb: []
      optionsc: []
      optiona: {}
      optionb: {}
      optionc: {}

    MyAPI.$watch 'ns.objecta', (values) ->
      $scope.ns.optionsa = values
    MyAPI.$watch 'ns.objectb', (values) ->
      $scope.ns.optionsb = values

    $scope.$watch 'ns.optionsa', (valuea) ->
      MyAPI.get 'objectb', valuea.id

    MyAPI.get 'objecta'

.directive 'optiona', ->
   restrict: 'E'
   require: '^filters'
   templateUrl: 'directive.optiona.html'

.directive 'optionb', ->
   restrict: 'E'
   require: '^filters'
   templateUrl: 'directive.optionb.html'

Templates

<!-- directive.optiona.html -->

<label>Select option a</label>
<select
    ng-model="$parent.ns.optiona"
    ng-options="i as i.name for i in $parent.ns.optionsa">
</select>

<!-- directive.optionb.html -->

<label>Select option a</label>
<select
    ng-model="$parent.ns.optionb"
    ng-options="i as i.name for i in $parent.ns.optionsb">
</select>

使用方式

<filters>
  <optiona></optiona>
  <optionb></optionb>
</filters>

上一个示例解决了所有问题,除非我将scope附加到filters指令时,子指令停止工作。我如何分享每个子指令的ng-model

我的控制器主模板中的

示例

<filters model="myfilter">
  <optiona></optiona>
  <optionb></optionb>
</filters>

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:0)

我找到了以下解决方案:通过每个过滤器移动选择选项并使用控制器更新主要指令,但是每个过滤器都需要model属性,即使没有使用该属性

使用方式

  

.coffee

for directiveName in ['optiona', 'optionb']    
  do (directiveName)
    .directive 'directiveName', ->
       restrict: 'E'
       require: '^filters'
       templateUrl: 'directive.' + directiveName + '.html'
       scope: { localModel: "=model" }
       controller: ($scope) ->
          $scope.$watch 'localModel', (value) ->
              $scope.$parent.ns[directiveName] = value   

templates

<!-- directive.optiona.html -->

<label>Select option a</label>
<select
    ng-model="localModel"
    ng-options="i as i.name for i in $parent.ns.optionsa">
</select>

<!-- directive.optionb.html -->

<label>Select option a</label>
<select
    ng-model="localModel"
    ng-options="i as i.name for i in $parent.ns.optionsb">
</select>

答案 1 :(得分:-1)

解决此问题的一种方法是以便于实现所需内容的格式对数据建模。

如果您的模型变为分层,您可以在没有指令的情况下实现此目的。模型结构为

$scope.optionsa=[{
                   prop1:"",
                   prop2:"", 
                   optionsb:[{
                              prop1:"",
                              optionc:[{},{}]
                            },{},{}]
                }]

所以你的选择变成了

<select ng-model="current_optiona" ng-options="a as a.name for a in optionsa"></select>
<!-- optionsb is built when current_optiona change -->
<select ng-model="current_optionb" ng-options="b as b.name for b in current_optiona.optionsb"></select>
<!-- optionsc is built when current_optionb change -->
<select ng-model="current_optionc" ng-options="c as c.name for c in current_optionb.optionsc"></select>