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

The 'angular way' of adding stored state to an application

本文关键字:状态 存储 添加 应用程序 方式      更新时间:2023-09-26

我们正在使用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);
        }
    }
});

然后呢?我如何在"全局"意义上访问完成的变量?事实上,下一步似乎并不明显,这表明我已经走错了。

在angular应用中存储和跟踪多个补全变量(在多个作用域?)的最好方法是什么?

编辑

我想我可能需要包括更多的细节来真正揭示我的问题:
假设我能够在每个engi -completable指令的作用域中添加一个'completable'属性,当用户点击一个按钮组件时,它会触发一个相应的弹出组件(通过对DOM元素的id引用),我如何引用弹出组件的角作用域来改变'completable'属性?

我知道这个问题的框架可能是有缺陷的,但是,如果是的话,我想知道在angular中,什么是"正确"的方法。

谢谢。

订阅事件是在控制器之间共享数据的好方法。下面是一个示例,向另一个控制器共享一个注释已加载完成,'controller1'将跟踪所有已加载的注释。

等待查看谁被加载的控制器示例:

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中,并且仅将数据存储在需要它的模型中。如果您更改页面,它还可以防止存储这些数据的内存泄漏。

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

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

主要的替代方案是使用一个共享服务来管理共享状态,这允许没有状态复制。服务是单例的,因此您可能认为它们不能很好地管理多个唯一的状态,但是它们可以很好地保存状态的映射(或数组),并监视更改。

一个共享服务的方法看起来像这样:

// 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
      });
    }
  }
}]);

共享服务会产生更多的观察者,因此请记住这一点。但是它将状态保持在一个地方——非常适合于保持同步——并且感觉更健壮一些。