我们正在使用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'属性?
我明白,即使问题的框架可能存在缺陷,但如果是这样的话,我想知道以正确的方式做什么是'正确的'。
感谢。
答案 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
});
}
}
}]);
共享服务会招致更多观察者,所以请记住这一点。但是它将状态保持在一个地方 - 非常适合保持同步 - 并且感觉更加强大。