将存储状态添加到应用程序的“角度方式”

时间:2016-08-24 13:05:41

标签: javascript angularjs angularjs-scope

我们正在使用Angularjs开发单页应用程序电子学习,我们已经到了需要跟踪某些组件是否“可完成”以及是否已完成的情况。

不幸的是,我几乎可以肯定我对Angularjs概念的理解是有缺陷的,所以在使用一些有争议的解决方案进行浮躁之前,我想知道实现这个目标的“角度方式”是什么。

我已将自定义属性指令'eng-completable'添加到组件的html模板(按钮单击时显示的弹出窗口)。我还可以添加一个(可能是假的)ng-model =“completed”变量声明......(下面的第一行是相关的 - 其他的都工作正常)

<div eng-completable ng-model="completed" class="hidden popup {{component.popup.type}}" id="{{component.popup.name}}" data-replaces="{{component.popup.replaces}}">
    <div ng-if="component.popup.type=='overlay'">
        <div class="float-right button close-button">X</div>
    </div>
    <p class="heading">{{component.popup.heading}}</p>
    <div class="popup-content">
        <div ng-if="0" ng-repeat-start="(innerIndex, component) in component.popup.popup_components"></div>
            <div ng-if="0" ng-repeat-start="(type, object) in component"></div>
                <div ng-attr-id="{{'p' + pageId + '-s' + skey + '-c' + ckey + '-component-' + index + '-innerComponent-' + innerIndex}}" ng-switch="type">
                    <div ng-switch-when="image" eng-image></div>
                    <div ng-switch-when="paragraph" eng-paragraph></div>
                </div>
            <div ng-if="0" ng-repeat-end></div>
        <div ng-if="0" ng-repeat-end></div>
    </div>
</div>

我已将相应的指令添加到app.js文件中:

app.directive('engCompletable', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            scope.completed = false;
            console.log("completable attribute encountered and triggered: scope.completed = "+scope.completed);
        }
    }
});

但那又怎么样?如何在“全局”意义上访问已完成的变量?事实上,下一步似乎并不明显,这表明我已经出错了。

在角度应用程序中存储和跟踪多个完成变量(在多个范围内?)的最佳方法是什么?

编辑

我想我可能需要包含更多细节才能真正揭示我的问题:
假设我能够在每个eng-completable指令的范围内添加'completable'属性,当用户单击触发相应弹出组件的按钮组件时(通过对DOM元素的id引用),我该怎么做参考弹出组件的角度范围来改变'completable'属性?

我明白,即使问题的框架可能存在缺陷,但如果是这样的话,我想知道以正确的方式做什么是'正确的'。

感谢。

2 个答案:

答案 0 :(得分:1)

订阅事件是在控制器之间共享数据的好方法。这是一个向另一个控制器共享注释已完成加载的示例,以及&#39; controller1&#39;将跟踪所有已加载的评论。

等待查看加载对象的控制器示例:

angular.module('app').controller('controller1', ['$scope', '$rootScope', function controller1($scope, $rootScope) {

    var unsubscribe = $rootScope.$on('comment:loaded', commentLoaded);    

    $scope.$on('$destroy', function removeBindings() {
        unsubscribe();
    });

    var commentIdsLoaded = {};
    function commentLoaded(event, comment) {
        commentIdsLoaded[comment.id] = true;
    }

});

正在通知评论的控制器

angular.module('app').controller('controller2', ['$scope', '$rootScope', function controller2($scope, $rootScope) {

    function commentFinishedLoading(comment) {
        $rootScope.$emit('comment:loaded', comment);
    }

});

此解决方案允许您管理注释,而无需将其存储在$ rootScope中,只将数据存储在需要它的模型中。如果您更改页面,它还可以防止发生存储数据的内存泄漏。

答案 1 :(得分:0)

事件可能是在组件之间共享这种状态的最轻量级方式,通常是我开始处理此类问题的方式。

通过更多的组件间交互,事件可能变得麻烦且容易出错。当有许多发射器和/或侦听器时,您需要确保正确的组件正在处理正确的消息。您在每个相关组件中基本上也是重复状态,这使得很容易出现不同步问题。

主要的替代方案是使用共享服务来管理共享状态,这样就不会出现状态重复。服务是单身,所以你可能认为它们不能很好地管理多个独特的状态,但它们可以很好地保存状态的地图(或阵列),并观察变化。

共享服务方法可能类似于:

// Shared service
angular.module('app').service('completables', function(){
  // A map of, perhaps { exerciseId : isCompleted } 
  var _states = {};
  // You could put getters and setters on here to be more explicit
  return { 'states': _states }
});

// Some high-level controller
angular.module('app').controller('highLevel', ['completables', function(completables){
  $scope.completables = completables;
  $scope.$watch('completeables.states', function(oldStates, newStates){
    // Do something whenever ANY states change
  });  
});

// Low-level directives
app.directive('engCompletable', ['completables', function(completables){ 
  return {
    scope: { exercise: '=' },
    link: function(scope, element, attrs) {

      // Set initial (shared) state
      completeables.state[scope.exercise.id] = false;

      // Triggered by user interaction
      scope.completeExercise = function(){
        completeables.state[scope.exercise.id] = true;   
      };

      // You could also watch for external changes to just this exercise
      scope.completables = completeables;
      scope.$watch('completables.' + [scope.exercise.id], function(oldState, newState){
        // Do something when changed externally
      });
    }
  }
}]);

共享服务会招致更多观察者,所以请记住这一点。但是它将状态保持在一个地方 - 非常适合保持同步 - 并且感觉更加强大。