Search code examples
javascriptangularjsangular-ui-routerstateangularjs-controller

Update $state variable in 1 module from another


https://plnkr.co/edit/PWuKuVw9Dn9UJy6l8hZv?p=preview

I have 3 modules, routerApp, tickers and tags. Basically trying to rebuild my app out of smaller mini-apps.

The routerApp template contains the 2 directives for the other modules.

Expected

When you login, then click on the Count button in the tickers.component, I want to send the counter var into the tags.component $scope via $state.go.

Result

Nothing happens. No $state/variable update in the tags.component


Plnkr app.js code:

// TICKERS app module
var tickers = angular.module('tickers', ['ui.router'])

tickers.config(function($stateProvider) {
  
  const tickers = {
    name: 'tickers',
    url: '/tickers',
    parent: 'dashboard',
    templateUrl: 'tickers-list.html',
    bindToController: true,
    controllerAs: 'tik',
    controller: function() {

    }
  }
  
  $stateProvider
    .state(tickers);
  
})

tickers.component('tickersModule', {
  templateUrl: 'tickers-list.html',
  controller: function($scope, $state) {
    console.log('Tickers init')
    
    $scope.counter = 0;
    
    $scope.increase = function() {
      $scope.counter++;
      console.log('increase', $scope.counter)
      $state.go('dashboard.tags', { counter: $scope.counter });
    }
  }
})

// TAGS app module
var tags = angular.module('tags', ['ui.router'])

tags.config(function($stateProvider) {
  
  const tags = {
    name: 'tags',
    url: '/tags?counter',
    parent: 'dashboard',
    params: {
      counter: 0
    },
    templateUrl: 'tags-list.html',
    bindToController: true,
    controllerAs: 'tags',
    controller: function($state) {

    }
  }
  
  $stateProvider
    .state(tags);
  
})

tags.component('tagsModule', {
  templateUrl: 'tags-list.html',
  controller: function($scope, $state) {
    // Expecting this to update:
    console.log('Tags init', $state)
    $scope.counter = $state.params.counter;
  }
})

// MAIN ROUTERAPP module
var routerApp = angular.module('routerApp', ['ui.router', 'tickers', 'tags']);

routerApp.config(function($stateProvider, $urlRouterProvider) {
    
    $urlRouterProvider.otherwise('/login');

    const login = {
      name: 'login',
      url: '/login',
      templateUrl: 'login.html',
      bindToController: true,
      controllerAs: 'l',
      controller: function($state) {
        this.login = function() {
          $state.go('dashboard', {})
        }
      }
    }

    const dashboard = {
      name: 'dashboard',
      url: '/dashboard',
      templateUrl: 'dashboard.html',
      controller: function() {
        
      }
    }

    $stateProvider
        .state(login)
        .state(dashboard);

})

dashboard.html

<div class="jumbotron text-center">
    <h1>The Dashboard</h1>
</div>

<div class="row">
  <tickers-module></tickers-module>
  <tags-module></tags-module>
</div>

The function in the tickers component that is trying to update the $state of the tags component:

$scope.increase = function() {
  $scope.counter++;
  console.log('increase', $scope.counter)
  $state.go('dashboard.tags', { counter: $scope.counter });
}

Also tried: $state.go('tags', { counter: $scope.counter });

Finally the tags.component. Note that here I'm not seeing the $scope.counter update nor the controller for the component getting refreshed due to a state change.

tags.component('tagsModule', {
  templateUrl: 'tags-list.html',
  controller: function($scope, $state) {
    console.log('Tags init', $state)
    $scope.counter = $state.params.counter;
  }
})

Is the way I am architecting this going to work? What am I missing?


Update: Added some $rootScope events to watch for $state changes, hope this helps:

This is after clicking the login button and going from the login state to the dashboard state, but still nothing for clicking on the Count button.

enter image description here


Solution

  • Figured it out!

    https://plnkr.co/edit/CvJLXKYh8Yf5npNa2mUh?p=preview

    My problem was that in the $state object tags, I was using the same template as the tags.component.

    Instead I needed to change it to something like <p>{{ counter }}</p>

    var tags = angular.module('tags', ['ui.router'])
    
    tags.config(function($stateProvider) {
      
      const tags = {
        name: 'tags',
        url: '/tags',
        parent: 'dashboard',
        params: {
          counter: 0
        },
        template: '<p>{{ counter }}</p>',
        bindToController: true,
        controller: function($scope, $state) {
          console.log('tags state object', $state)
          $scope.counter = $state.params.counter;
        }
      }
      
      $stateProvider
        .state(tags);
      
    })
    
    tags.component('tagsModule', {
      templateUrl: 'tags-module-template.html',
      controller: function($scope, $state) {
        
      }
    })
    

    Then in my tags-module.template.html I needed to add a <div ui-view></div>

    <div class="jumbotron text-center">
        <h2>Tags list</h2>
        <div ui-view></div> // <- here and this is where the $state object updates
        {{ counter }}
    </div>