【问题标题】:Modal with AngularJS isolated scope具有 AngularJS 隔离范围的模态
【发布时间】:2015-10-18 14:31:06
【问题描述】:

我正在尝试创建一个 AngularJS 指令来处理模式窗口,但我不知道如何隔离范围。我的目标是有一个模式窗口来添加一个新的位置。我希望该指令使用来自父范围的任何所需数据填充模态并处理保存按钮单击。我使用父作用域得到了这个工作,但我无法让它与隔离作用域一起工作。

父控制器有一个位置属性,在这种情况下,这是我需要的唯一父属性。 newLocation 对象应与父范围隔离。当我添加隔离范围时,不会填充名称输入,并且不会触发单击处理程序。范围声明只允许 @、= 和 & 属性,所以我不能在那里增加它,并且在链接中添加属性没有效果。

指令:

        angular.module('pw').directive('addLocationModal', [
        'appApi', function (appApi) {
            return {
                restrict: 'A',
                scope: {
                    locations: '='
                },
                link: function (scope, element, attrs) {
                    scope.newLocation = {
                        name: 'xxx'
                    };
                    scope.saveLocation = function () {
                        alert('save location');
                    };
                }
            };
        }
    ]);

模态:

<div class="modal fade" id="add-location-modal" add-location-modal>
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal">
                <span>&times;</span>
            </button>
            <h4 class="modal-title">Add Location</h4>
        </div>
        <div class="modal-body">
                <div class="form-group">
                    <label>Name</label>
                    <input type="text" class="form-control" ng-model="newLocation.name" required />
                </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            <button type="button" class="btn btn-primary" ng-click="saveLocation()">Save</button>
        </div>
    </div>
</div>

【问题讨论】:

  • 可以提供jsfiddle或者plnkr吗?
  • 如果你需要保持作用域隔离,你应该使用前缀 @ 传递初始值并使用前缀 & 让父作用域知道在保存功能上对位置所做的更改
  • 我创建了一个 Plunker -- plnkr.co/edit/FxtSPHR3QFJOd0PTnMiI 但即使没有隔离范围,它也无法工作,我对此没有耐心。
  • 摆脱 bootstrap.js 并使用 angular-ui-bootstrap 会简单得多。无需重新发明轮子
  • 有趣的项目,但我不想完全致力于 Angular。

标签: angularjs twitter-bootstrap


【解决方案1】:

你需要移动 div

<div class="modal-dialog">...

到指令的模板

return {
    restrict: 'A',
    templateUrl : 'view.html',
    scope: {
       locations: '='
    },
    link: function(scope, element, attrs) {
         scope.newLocation = {
             name: 'xxx'
         };
        scope.saveLocation = function() {
           alert('save location');
        };
    }
};

view.html

<div class="modal-dialog">
   .....
   .....
</div>

index.html

<div class="modal fade" id="add-location-modal" add-location-modal>

</div>

directive html 应该针对指令作用域进行编译(将作用域数据和函数绑定到视图更有可能将指令绑定到ng-clickng-model 等作用域,如果不是针对所需作用域编译的话它不会像我们预期的那样糟糕),在这里您没有指令模板,并且您假设 index.html 中的指令 div 之间的 html 行为与 directive html 相同,但实际上并非如此。

&lt;div class="modal fade" id="add-location-modal" add-location-modal&gt; 的内部内容移动到指令的模板将解决这个问题。因为指令ng-modelng-click 是针对指令范围而不是父范围编译的。

这里是简单的DEMO

更新 - 您的第一条评论的解决方案

您可以在指令 div 之间编译 html 并附加到指令 compile 函数中的相同元素,

compile: function(tElement, tAttr, transclude) {
  var contents = tElement.contents().remove();
  var compiledContents;
  return function(scope, iElement, iAttr) {
    if (!compiledContents) {
      compiledContents = $compile(contents, transclude);
    }
    compiledContents(scope, function(clone, scope) {
      iElement.append(clone);
    });
  };
},

并将您的范围属性移动到指令controller 函数

 controller: function($scope) {

     $scope.newLocation = {
        name: 'xxx'
     };

     $scope.saveLocation = function() {
        alert('save location');
     };
}

这是更新后的DEMO

【讨论】:

  • 在我的例子中,模态模板是在页面上呈现的 ASP.NET Razor 局部视图。那么,具有独立作用域的指令只能访问在 template 或 templateUrl 中声明的 DOM 元素?令我印象深刻的是,您能够在比我弄清楚如何使用 Plunker 的时间更短的时间内输入此答案并创建 Plunker。 :-)
  • 嗨@JamieIde 我更新了答案,请看一下:),是的指令将编译html 在指令templatetemplateUrl 在此编译阶段指令中定义,如ng-clickng-model 与范围绑定。并且大声笑是的 plunker 证明了一些样板来启动 angularjs plunker。单击位于菜单项new 右侧的向下箭头并选择一个angularjs :)
  • 感谢您的更新。我在使用 Plunker 时遇到了两个问题:1) 第一个库选择是预发布版本;2) 我找不到添加 Bootstrap 的 JavaScript 组件的选项,必须找到一个 CDN。
【解决方案2】:

我想我可能已经明白了。该模式不适用于打开和关闭,但我分叉了 @K.Toress 的 plunk,我认为我让隔离范围工作。

http://plnkr.co/edit/8DwJqc?p=preview

重要的部分。

  1. 您需要使用控制器和指令。您需要控制器中的范围开始。

    app.controller('MainCtrl', function($scope) {
      $scope.locations = [{name: "loc1", level: 1}, {name: "loc2", level: 2}]
    });
    
  2. 当您定义指令时,指令范围将有一个directiveLocations 对象。

    scope: {
      directiveLocations: '=locations-attr'
    },
    
  3. 它从元素的locations-attr 属性中获取该对象的名称,即“locations”。

    <div class="modal" add-location-modal locations-attr="locations">
    
  4. 所以现在我们已经将控制器 $scope.locations 映射到指令范围内的 directiveLocations。

  5. 要将位置保存回父控制器范围,您只需附加到指令位置列表,因为它现在与父 $scope.locations 相同。

    var tempLocation = {
      name: scope.newLocation.name,
      level: scope.newLocation.level
    }
    scope.directiveLocations.push(tempLocation);
    

我不知道为什么我必须在这里创建一个新对象。将同一个对象添加回父范围有些奇怪。

【讨论】:

  • 我在使用 Angular 和引导模式时遇到了一点麻烦。删除“淡入淡出”类(以及动画)有所帮助。
猜你喜欢
  • 2017-06-23
  • 2019-10-21
  • 2014-08-13
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多