Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change shared data in ui-router

I want to ask you about sharing data between states in ui-router. This is my example of $stateProvider

$stateProvider.state('start',{
    url:"/inicio",
    templateUrl:"./app/templates/start.html",
    abstract: true,
    data:{
        title: 'Hello world'
    },
    controller: 'aplicacionController',

}).state('start.App',{
    url:"/aplicacion",
    templateUrl:"./app/templates/escritorio.html"
}).state('start.App.onlyMenu',{
    url:"/ms",
    views:{
        'menu':{
            templateUrl:"./app/templates/menu.html",
            controller:'menuController'
        },
        'mainFrame':{
            templateUrl: './app/templates/whiteBoard.html',
            controller:'whiteBoardController'
        }
    }
}).state('start.app.JqPlotCharts',{
    url:"/jqp",
    views:{
        'menu':{
            templateUrl:"./app/templates/menu.html",
            controller:'menuController'
        },
        'mainFrame':{
            templateUrl: './app/templates/jqplotcharts.html',
            controller:'jqplotCtrl'
        }
    }
});

As you can see, I have a parent state called start with a data field which have the title property with the value "Hello world". The aplicacionController has two missions: First is to read the value of title and store in a $scope variable called title:

$scope.title = $state.current.data.title;

And the second is watch if title is changed and, if it has happened, update the value of $state.current.data.title:

$scope.$watch('title', function(){
    $state.current.data.titulo = $scope.title;
});

Of course, inside the template start.html, I have a small form to change this value:

<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <a class="navbar-brand" href="#">{{title}}</a>
    </div>

   <!-- Collect the nav links, forms, and other content for toggling -->
   <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <form class="navbar-form navbar-left" role="search">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search" ng-model="title">
        </div>
      </form>
   </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

My intention is that all the children states reads the value of title and, when it is changed from the parent template, the value is updated in the children states, too. However, it never happens. The value is updated in the parent state but never in the children.

What am I missing?

Thank you

like image 453
Adrian Avatar asked Jan 19 '26 11:01

Adrian


1 Answers

I would try to explain why this requirement should be thought a bit differently.

Firstly the .data setting of the state (see Attach Custom Data to State Objects), should be treated as a configuration part. Meaning: readonly, constant. Also, as the .data inheritance shows, there is some smart mechanism how to provide almsot the opposite functionality than required above:

Inherited Custom Data

Child states will inherit data properties from parent state(s), which they can overwrite.

$stateProvider.state('parent', {
      data:{
         customData1:  "Hello",
         customData2:  "World!"
      }
   })
   .state('parent.child', {
      data:{
         // customData1 inherited from 'parent'
         // but we'll overwrite customData2
         customData2:  "UI-Router!"
      }
   });

$rootScope.$on('$stateChangeStart', function(event, toState){ 
    var greeting = toState.data.customData1 + " " + toState.data.customData2;
    console.log(greeting);

    // Would print "Hello World!" when 'parent' is activated
    // Would print "Hello UI-Router!" when 'parent.child' is activated
})

As we can see, this is what we can do with configuration of our state, with the custom .data object.

But how to solve the issue we have? Well, there is really native Angular JS solution:

Service.

Such object will be working as a singleton. We can have it anyhwere, we can place it into $rootScope ... we can do a lot. But mostly, we can use it for data sharing. See similar example and solution here:

  • Attach data dynamically to state.go function and retrieve in resolve property

And this is a drafted service called Settings

.factory('Settings', function(){
  return {
    Property1: null,
    Property2: null,
    ...
  };
})

A plunker of this example.

like image 180
Radim Köhler Avatar answered Jan 21 '26 23:01

Radim Köhler