工厂中的 $rootScope.$broadcast 不能更改其他 $scope 中的值
$rootScope.$broadcast in factory cannot change a value in other $scope
我有一个主页模板(离子)有一个像这样的标签:
<ion-tab title="ACCOUNT" icon="ion-trophy" href="#/home/account" badge="levelBadge" badge-style="badge-assertive" on-select="enteringAccount()" on-deselect="leavingAccount()" ng-controller="homeTabCtrl">
<ion-nav-view name="tab-account" animation="slide-left-right"></ion-nav-view>
</ion-tab>
我希望在其他范围内发生某些事情时更改 levelBadge 值。
在其他范围内,我有这个控制器(lessonCtrl)。单击此视图上的按钮时,控制器会在该控制器内调用此函数:
$scope.testBoardcast = function() {
MyFirebaseService.testBoardcast();
}
在 MyFirebaseService(一个工厂)中,我有这个功能:
function testBoardcast() {
$rootScope.$broadcast('level-up', 2);
}
在我的主页模板 homeTabCtrl 中,我正在收听这样的升级事件:
$rootScope.$on('level-up', function(event, data) {
console.log ("App received level up boardcast: " + data);
$scope.levelBadge = parseInt(data, 10);
});
但问题是,当我单击 lessonCtrl 上的按钮时,levelBadge 没有得到更新并且徽章不会显示,甚至控制台日志“App received level up boardcast:”在我单击按钮后立即显示。
如果我像这样只监听 homeTabCtrl 范围:
$scope.$on('level-up', function(event, data) {
console.log ("App received level up boardcast: " + data);
$scope.levelBadge = parseInt(data, 10);
});
当我点击 lessonCtrl 上的按钮时没有任何反应。
我不知道如何在lessonCtrl中以完全不同的状态单击按钮时让levelBadge动态变化。
更新:这是我的 ui-路线:
.state('home', {
cache: false,
abstract: true,
url: "/home",
templateUrl: "app/home/home.html",
controller: 'homeTabCtrl',
onEnter: function($state, MyFirebaseService) {
var userId = MyFirebaseService.LoginUserId();
if (!userId) {
$state.go('auth.signin');
};
}
})
.state('home.courses', {
cache: false,
url: "/courses",
views: {
"tab-courses": {
templateUrl: "app/home/courses.html"
}
}
})
.state('app', {
abstract: true,
url: "/app",
templateUrl: "app/layout/menu-layout.html",
controller: 'AppCtrl'
})
.state('app.lesson', {
cache: false,
url: "/lesson/:id",
views: {
'mainContent': {
templateUrl: "app/all/lesson-detail.html",
controller: "lessonCtrl"
},
}
})
所以家是一个抽象的状态。选项卡位于主页模板中。 lessonCtrl 实际上处于另一种称为 App 的抽象状态。它们不是合作伙伴或子范围。只有 2 个不同的范围。
我需要查看您的 ui-路由器配置 ($stateProvider) 以进一步调试您的代码未按预期工作的原因。这很可能是由于在调用 $broadcast 时未实例化 homeTabCtrl。
一种解决方案是使用服务。对服务进行更改,并在 homeTabCtrl 中监视该服务。
在你的课程控制器调用中
Level.levelUp(1);
然后在你的 homeTab 控制器中观察 Level 服务的变化
$scope.$watch(
function () {
return Level.currentLevel();
},
function(newVal, oldVal) {
$scope.level = newVal;
}
);
这里是一个 plunker 设置这个结构:http://plnkr.co/edit/mAASNGNqr37k9n0RR89X?p=preview
编辑
看看这个 plunker,它设置了一个类似的视图层次结构:http://plnkr.co/edit/hyKECbyYAG8XzUh8x58K?p=preview。请注意当您导航到应用程序和主页状态时控制台日志如何打印初始化消息。
每次您从主页状态更改为应用程序状态时,主页控制器都会取消实例化,而应用程序控制器会被实例化(这个答案在某种程度上解释了流程:)。
所以当你转到应用状态时,主状态不能监听事件。单例服务将按您的需要工作,所以我建议使用它而不是 pub/sub 方法。
我有一个主页模板(离子)有一个像这样的标签:
<ion-tab title="ACCOUNT" icon="ion-trophy" href="#/home/account" badge="levelBadge" badge-style="badge-assertive" on-select="enteringAccount()" on-deselect="leavingAccount()" ng-controller="homeTabCtrl">
<ion-nav-view name="tab-account" animation="slide-left-right"></ion-nav-view>
</ion-tab>
我希望在其他范围内发生某些事情时更改 levelBadge 值。
在其他范围内,我有这个控制器(lessonCtrl)。单击此视图上的按钮时,控制器会在该控制器内调用此函数:
$scope.testBoardcast = function() {
MyFirebaseService.testBoardcast();
}
在 MyFirebaseService(一个工厂)中,我有这个功能:
function testBoardcast() {
$rootScope.$broadcast('level-up', 2);
}
在我的主页模板 homeTabCtrl 中,我正在收听这样的升级事件:
$rootScope.$on('level-up', function(event, data) {
console.log ("App received level up boardcast: " + data);
$scope.levelBadge = parseInt(data, 10);
});
但问题是,当我单击 lessonCtrl 上的按钮时,levelBadge 没有得到更新并且徽章不会显示,甚至控制台日志“App received level up boardcast:”在我单击按钮后立即显示。
如果我像这样只监听 homeTabCtrl 范围:
$scope.$on('level-up', function(event, data) {
console.log ("App received level up boardcast: " + data);
$scope.levelBadge = parseInt(data, 10);
});
当我点击 lessonCtrl 上的按钮时没有任何反应。
我不知道如何在lessonCtrl中以完全不同的状态单击按钮时让levelBadge动态变化。
更新:这是我的 ui-路线:
.state('home', {
cache: false,
abstract: true,
url: "/home",
templateUrl: "app/home/home.html",
controller: 'homeTabCtrl',
onEnter: function($state, MyFirebaseService) {
var userId = MyFirebaseService.LoginUserId();
if (!userId) {
$state.go('auth.signin');
};
}
})
.state('home.courses', {
cache: false,
url: "/courses",
views: {
"tab-courses": {
templateUrl: "app/home/courses.html"
}
}
})
.state('app', {
abstract: true,
url: "/app",
templateUrl: "app/layout/menu-layout.html",
controller: 'AppCtrl'
})
.state('app.lesson', {
cache: false,
url: "/lesson/:id",
views: {
'mainContent': {
templateUrl: "app/all/lesson-detail.html",
controller: "lessonCtrl"
},
}
})
所以家是一个抽象的状态。选项卡位于主页模板中。 lessonCtrl 实际上处于另一种称为 App 的抽象状态。它们不是合作伙伴或子范围。只有 2 个不同的范围。
我需要查看您的 ui-路由器配置 ($stateProvider) 以进一步调试您的代码未按预期工作的原因。这很可能是由于在调用 $broadcast 时未实例化 homeTabCtrl。
一种解决方案是使用服务。对服务进行更改,并在 homeTabCtrl 中监视该服务。
在你的课程控制器调用中
Level.levelUp(1);
然后在你的 homeTab 控制器中观察 Level 服务的变化
$scope.$watch(
function () {
return Level.currentLevel();
},
function(newVal, oldVal) {
$scope.level = newVal;
}
);
这里是一个 plunker 设置这个结构:http://plnkr.co/edit/mAASNGNqr37k9n0RR89X?p=preview
编辑
看看这个 plunker,它设置了一个类似的视图层次结构:http://plnkr.co/edit/hyKECbyYAG8XzUh8x58K?p=preview。请注意当您导航到应用程序和主页状态时控制台日志如何打印初始化消息。
每次您从主页状态更改为应用程序状态时,主页控制器都会取消实例化,而应用程序控制器会被实例化(这个答案在某种程度上解释了流程:
所以当你转到应用状态时,主状态不能监听事件。单例服务将按您的需要工作,所以我建议使用它而不是 pub/sub 方法。