如何在视图中多次正确使用相同的AngularJS 1.5组件?

时间:2016-11-08 10:27:26

标签: javascript angularjs

我正在使用AngularJS 1.5的新组件创建一组小部件。问题是,当多次使用相同的窗口小部件时,它们会以某种方式共享其控制器或范围。我认为有关组件的一个问题是它们的范围是完全孤立的吗?

我的主要html模板包含小部件:

<widget-list
    title="Books"
    class="col-xs-12 col-md-4">
</widget-list>

<widget-list
    title="Movies"
    class="col-xs-12 col-md-4">
</widget-list>

<widget-list
    title="Albums"
    class="col-xs-12 col-md-4">
</widget-list>

我的小部件模板:

<div class="widget widget-list">
    <div class="panel b-a">

        <div class="panel-heading b-b b-light">
            <h5>{{$widget.title}}</h5>
            <div class="pull-right">
                <button type="button" class="btn btn-default btn-sm" ng-click="$widget.doSomething()">
                    Do something
                </button>
            </div>
        </div>

        <div class="panel-content">
            {{$widget.content || 'No content'}}
        </div>

    </div>
</div>

我的小部件组件:

app.component('widgetList', {
    templateUrl: 'template/widget/widget-list.html',
    bindings: {
        title   : '@',
    },
    controllerAs: '$widget',
    controller: function($timeout) {

        $widget = this;

        console.log('Title on init: ', $widget.title)

        $timeout(function() {
            console.log('Title after 3 seconds: ', $widget.title)
        }, 3000)

        $widget.doSomething = function() {
            $widget.content = "Something";
        }
    }
});

运行我的代码时,这就是我的控制台的样子:

Title on init: Books
Title on init: Movies
Title on init: Albums
(3) Title after 3 seconds: Albums

渲染后,所有三个小部件都在其模板中显示No content。但是,当点击三个小部件中的任何一个中的doSomething()按钮时,只有最后一个小部件的内容更新为Something

这里发生了什么?为什么我的组件没有“隔离”?

2 个答案:

答案 0 :(得分:3)

看起来你有一个名为$ widget的全局变量,试试这个:

var $widget = this;

而不是

$widget = this;

由于$ widget变量包含对最近初始化的控制器的引用(在本例中为第三个组件的控制器),因此它会造成混乱。

答案 1 :(得分:2)

您的代码的问题在于您在窗口范围内声明$widget,这就是您的控制器打印最后一个值的原因,因为每次控制器实例化时它都会被覆盖。请改用var $widget代码,您的代码就可以正常使用。

以下代码段解决了这个问题:

angular.module('app', [])
  .component('widgetList', {
    templateUrl: 'template/widget/widget-list.html',
    bindings: {
      title: '@',
    },
    controllerAs: '$widget',
    controller: WidgetListController
  });

function WidgetListController($timeout) {

  var $widget = this;

  console.log('Title on init: ', $widget.title)

  $timeout(function() {
    console.log('Title after 3 seconds: ', $widget.title)
  }, 3000)

  $widget.doSomething = function() {
    $widget.content = "Something";
  }
}

angular.element(document).ready(function() {
  angular.bootstrap(document, ['app']);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script>
<widget-list title="Books" class="col-xs-12 col-md-4">
</widget-list>

<widget-list title="Movies" class="col-xs-12 col-md-4">
</widget-list>

<widget-list title="Albums" class="col-xs-12 col-md-4">
</widget-list>

<script type="text/ng-template" id="template/widget/widget-list.html">
  <div class="widget widget-list">
    <div class="panel b-a">

      <div class="panel-heading b-b b-light">
        <h5>{{$widget.title}}</h5>
        <div class="pull-right">
          <button type="button" class="btn btn-default btn-sm" ng-click="$widget.doSomething()">
            Do something
          </button>
        </div>
      </div>

      <div class="panel-content">
        {{$widget.content || 'No content'}}
      </div>

    </div>
  </div>
</script>