$rootScope.$broadcast в фабрике не может изменить значение в другом $scope

У меня есть домашний шаблон (ionic) с такой вкладкой:

<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 менялось, когда что-то происходит в другой области.

В другой области у меня есть этот контроллер (lesonCtrl). При нажатии кнопки в этом представлении контроллер вызывает эту функцию внутри этого контроллера:

$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); 
    });

Но проблема в том, что когда я нажимаю кнопку на урокеCtrl, levelBadge не обновляется, и значок не будет отображаться даже в журнале консоли. Приложение получило повышение уровня. Boardcast: отображается сразу после того, как я нажал кнопку.

Если я слушаю только область homeTabCtrl следующим образом:

$scope.$on('level-up', function(event, data) {
        console.log ("App received level up boardcast: " + data);
        $scope.levelBadge = parseInt(data, 10); 
    });

Ничего не происходит, когда я нажимаю кнопку на урокеCtrl.

Я понятия не имею, как заставить levelBadge динамически изменяться, когда я нажимаю кнопку в совершенно другом состоянии вleuranceCtrl.

ОБНОВЛЕНИЕ: Вот мой пользовательский интерфейс:

.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"
    },
  }
})

Итак, дом — это абстрактное состояние. Вкладки находятся в домашнем шаблоне. Урок Ctrl на самом деле находится в другом абстрактном состоянии, называемом App. Они не являются партнерской или дочерней областью. Просто 2 разных прицела.


person Hugh Hou    schedule 12.06.2015    source источник


Ответы (1)


Мне нужно увидеть вашу конфигурацию ui-router ($stateProvider) для дальнейшей отладки, почему ваш код не работает должным образом. Скорее всего, это связано с тем, что экземпляр homeTabCtrl не создается во время вызова $broadcast.

Одним из решений является использование службы. Внесите свои изменения в службу и в своем homeTabCtrl следите за этой службой.

В вызове контроллера урока

Level.levelUp(1);

Затем в вашем контроллере homeTab наблюдайте за изменением сервиса Level.

$scope.$watch(
  function () {
    return Level.currentLevel();
  },
  function(newVal, oldVal) {
    $scope.level = newVal;
  }
);

Вот плункер, настраивающий эту структуру: =предварительный просмотр


Изменить

Посмотрите на этот планкер, который устанавливает аналогичную иерархию представлений: http://plnkr.co/edit/hyKECbyYAG8XzUh8x58K?p=preview. Обратите внимание, как журнал консоли печатает сообщение об инициализации, когда вы переходите к приложению и домашнему состоянию и обратно.

Каждый раз, когда вы переходите из домашнего состояния в состояние приложения, экземпляр домашнего контроллера не создается, а экземпляр контроллера приложения создается (этот ответ несколько объясняет поток: создание экземпляра контроллера angularjs, ui-router).

Поэтому, когда вы переходите к состояниям приложения, домашние состояния не могут прослушивать события. Служба singleton будет работать так, как вы хотите, поэтому я бы предложил использовать ее вместо подхода pub/sub.

person soote    schedule 12.06.2015
comment
Что вы имеете в виду, что экземпляр homeTabCtrl не создается во время вызова $broadcast? Пользователю необходимо сначала перейти к home.courses (какой экземпляр homeTabCtrl создан?), затем перейти к app.lessons, а затем выбрать урок для просмотра в app.lesson.:id. Урок Ctrl вызывает здесь трансляцию уровня фабрики. Поскольку console.log (приложение получило повышение уровня доски объявлений) работает сразу после того, как я нажму кнопку повышения уровня в урокеCtrl, я предполагаю, что создан экземпляр homeTabCtrl? Но $scope.levelBadge внутри $rootScope.$on не обновлялся (представление не обновлялось). - person Hugh Hou; 12.06.2015
comment
Ух ты. Я понятия не имею, что это работает таким образом. Это особое поведение Angular? Я думаю, что делаю фундаментальную архитектурную ошибку? Я как бы группирую функции/приложения в разные папки с собственным абстрактным состоянием. Какой-нибудь хороший ресурс, который вы можете указать мне, чтобы лучше понять это? Кстати, ваш метод одноэлементного обслуживания работает отлично. - person Hugh Hou; 13.06.2015