How I can pass object from page to page with $stateProvider in angularjs? Can you give me some code snippet? I'm new in angular
Thanks in advance
When defining a state you have a few options:
.state('my-state', {
url: '/my-state',
templateUrl: 'my-state-url',
params: {
myProperty: 'some value',
}
})
Then you can do this while changing state:
$state.go('my-state', {myProperty: 'new value'});
In the state controller you can access the myProperty like so:
$scope.myProperty = $stateParams.myProperty;
But depending on the data you want to pass, a custom angular service can/should be used. There's a good tutorial regarding this subject here.
You don't pass the object, you pass the object's ID which will allow you to retrieve the object.
You should use ui-router for this.
When definining states you will define the URL as something like ...
"url": '/an/example/path/:objectid',
"controller": "YourControllerForThisView",
USE OF THE COLON DEFINES THAT THIS IS A VARIABLE PARAMETER
Then in your controller you can access
state.params.objectid
Then in your controller you will call a method like ...
myService.getObjectFromList(state.params.objectid)
OR
myService.getObjectFromHttpCall(state.params.objectid)
to populate the object to be used when rendering the view
Hope this helps
If you're looking to "pass" objects only between a few (e.g., two or three) views, then using $stateProvider would suffice. However, if the same objects shall be retrieved/modified by several different parts of the application, it would be better to place these objects in a service.
For instance, a factory may be created to store such an object.
(function () {
angular.module('myApp').
factory('myFactory', myFactory);
function myFactory() {
var object ={};
var service = {
getObject: getObject,
setObject: setObject,
setObjectProperty: setObjectProperty
};
return service;
function getObject() {
return object
}
function setObject(newObject) {
//Some modification logic here
object = newObject;
return object;
}
function setObjectProperty(property, value) {
//Modify/assign new object property here
return object;
}
}
})();
A controller can then use the factory to retrieve/modify the stored object.
(function () {
angular.module('myApp').
controller('MyController', MyController);
function MyController(myFactory) {
var vm = this,
someObject = { ... };
//Invoke public factory functions
vm.object = myFactory.setObject(someObject);
}
})();
I solved issue, the problem was in version of angular-ui-router, it jsut didn't work with version that I had, to be more concrete I got error when I try to add params on state
Related
I am currently using Angular 1.5. I am using ui-router as my primary navigation mechanism. I am leveraging Angular components.
I understand that I can use .resolve on my states to instantiate services which are then passed down through my component hierarchy (mostly using one-way bindings).
One of my components is called literatureList and is used in more than one route/state. The literatureList component makes use of a specific service called literatureListService. literatureListService is only used by literatureList. literatureListService takes a while to instantiate, and uses promises etc.
In each of the .state definitions then I need to have a .resolve that instantiates literatureListService. This means that I need to refer to this literatureListService in each of the .state.resolve objects. This doesn't seem very DRY to me.
What I'd really like to do is remove the literatureListService references from the .state.resolve objects and 'resolve' the service from 'within' the literatureList component itself.
How do I code a 'resolve-style' mechanism within the literatureList component that will handle the async/promise nature of literatureListService? What is best practice for doing this?
Code snippets follow:
state snippets:
$stateProvider.state({
name: 'oxygen',
url: '/oxygen',
views: {
'spofroot': { template: '<oxygen booklist="$resolve.literatureListSvc"></oxygen>' }
},
resolve:{
literatureListSvc: function(literatureListService){
return literatureListService.getLiterature();
}
}
});
$stateProvider.state({
name: 'radium',
url: '/radium',
views: {
'spofroot': { template: '<radium booklist="$resolve.literatureListSvc"></radium>' }
},
resolve:{
literatureListSvc: function(literatureListService){
return literatureListService.getLiterature();
}
}
});
literatureListService:
angular.module('literature')
.factory('literatureListService',function($http,modelService){
// Remember that a factory returns an object, whereas a service is a constructor function that will be called with 'new'. See this for a discussion on the difference: http://blog.thoughtram.io/angular/2015/07/07/service-vs-factory-once-and-for-all.html
console.log('literatureListService factory is instantiating - this will only happen once for each full-page refresh');
// This is a factory, and therefore needs to return an object containing all the properties that we want to make available
var returnObject = {}; // Because this is a factory we will need to return a fully-formed object (if it was a service we would simply set properties on 'this' because the 'context' for the function would already have been set to an empty object
console.log('service instantiation reporting that modelManager.isDataDirty='+modelService.isDataDirty);
// The getLiterature method returns a promise, and therefore can only be consumed via a promise-based mechanism
returnObject.getLiterature = function($stateParams){
console.log('literatureService.getLiterature will now return a promise (via a call to $http)');
return $http({method: 'GET', url: 'http://localhost:3000/literature/'});
};
return returnObject;
});
oxygen component html:
<div>
This is the OXYGEN component which will now render a literature list, passing in bookList.data as books
<literature-list books="$ctrl.booklist.data"></literature-list>
</div>
oxygen component js
angular.module('frameworks')
.component('oxygen',{
templateUrl:"frontend/framework/frameworks/oxygenComponent.html",
controller:function($http){
var $ctrl = this;
console.log('Hello from the oxygen component controller with literatureListSvc='+$ctrl.booklist); // Bound objects NOT YET AVAILABLE!!!!!!
this.$onInit = function() {
//REMEMBER!!!! - the bound objects being passed into this component/controller are NOT available until just before the $onInit event fires
console.log('Hello from the oxygen component controller onInit event with bookList='+JSON.stringify($ctrl.booklist));
};
}
,bindings:{ // remember to make these lowercase!!!
booklist:'<'
}
});
literatureList component html:
<div>
{{$ctrl.narrative}}
<literature-line ng-repeat="literatureItem in $ctrl.books" wizard="fifteen" book="literatureItem" on-tut="$ctrl.updateItemViaParent(itm)">555 Repeat info={{literatureItem.title}}</literature-line>
</div>
literatureList component js
angular.module('literature')
.component('literatureList',{
templateUrl:'frontend/literature/literatureListComponent.html',
//template:'<br/>Template here33 {{$ctrl.listLocalV}} wtfff',
// controller:function(literatureListService){
controller:function(){//literatureListService){
var $ctrl=this;
this.narrative = "Narrative will unfold here";
this.updateItemViaParent = function(book){
this.narrative = 'just got notified of change to book:'+JSON.stringify(book);
};
this.$onInit = function(){
console.log('literatureList controller $onInit firing with books='+JSON.stringify($ctrl.books));
};
this.$onChanges = function(){
console.log('literatureList controller $onChanges firing');
};
},
bindings: {
books:'<'
}
});
As JavaScript in reference based, you can crete object in your service and access it in all three controllers that you need.
For Example:
function serviceA() {
var vm = this;
vm.testObject = {};
vm.promise1().then(function(response) {
vm.testObject = response;
})
}
function ControllerA($scope, serviceA) {
$scope.testA = service.testObject;
}
In this case, as soon as the promise is resolved, all the controllers will get the value of the response and can be used in the partials respecively
I want automatically refresh $scope.variable in both controllers to new value if data.variable in SharedFactory was changed:
.controller('FirstController', function($scope, SharedFactory) {
$scope.variable = SharedFactory.getVal();
})
.controller('SecondController', function($scope, SharedFactory) {
$scope.variable = SharedFactory.getVal();
SharedFactory.setVal("test string 2");
})
.factory("SharedFactory", function () {
var data = { // all variables by default
variable : 'test string'
};
return {
getVal: function () {
return data.variable
},
setVal: function (i) {
data.variable = i;
}
}
});
http://plnkr.co/edit/b1RNcl6Pz2iuRr2t2Q9x?p=preview
So at this example correct result must be "test string 2" in both controllers. How to do that?
Easiest (and possibly more efficient) would be to have a reference to SharedFactory.data directly in your controllers - rather than to SharedFactory.data.variable. That way, when the value of data.variable changes it would change in all controllers as you reference the data-variable rather than the specific value. Using primitives is generally not reccomended.
Another solution would be to use $scope.$watch in your controllers, and just watch for changes on the value and update the local-variable when it changes.
Because you are using primitive variable instead of using object so once you set it you actually lose your reference to original object, so instead of returning data object value (which is primitive) you can return all data object...
getVal: function () {
return data;
}
Here is update plunker...
I am using angular and grafana in my project.
I have a service -> dashboardViewStateSrv
My Service Code :
define([
'angular',
'lodash',
'jquery',
],
function (angular, _, $) {
'use strict';
var module = angular.module('grafana.services');
module.factory('dashboardViewStateSrv', function($location, $timeout) {
function DashboardViewState($scope) {
var self = this;
self.state = {};
self.panelScopes = [];
self.$scope = $scope;
// something
}
return {
create: function($scope) {
return new DashboardViewState($scope);
}
};
});
});
In My side menu controller :
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
if ($scope.dashboardViewState) {
if($scope.dashboardViewState.state.citreedepth){
depth = +$scope.dashboardViewState.state.citreedepth;
}
}
In My Dashboard controller :
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
DashboardViewState object is being created twice (Dashboard Ctrl and Side Menu ctrl).
I am creating DashboardViewState object twice, I want to avoid that. If I can avoid creating DashboardViewState object in Side Menu ctrl?
There should be only one view state. As per my understanding all the services are singleton in angular.
Please guide me what I can do?
Services are singletons, they are essentially a constructure function allowing you to use the this keyword inside them. They are instantiated once when first created then that instance is shared throughout your app.
Factories are, well, factories. Somewhere in Angular it will call Object.create() on the object your return from a factory. Meaning each call will return a new instance of it.
So in your use case your creating a new object twice. First by using a factory, then second by returning a new object from that factory.
This may help http://blog.thoughtram.io/angular/2015/07/07/service-vs-factory-once-and-for-all.html
So if you want a single instance of an object through your application you should use .service() not .factory();
If you want to instantiate a new Object only once you could use a service. Have the object as a property and a get method. The service could check if the object is already created and if not make it.
something like this (example code, not tested):
module.service('dashboardViewStateSrv', function($location, $timeout) {
this.object;
this.get = function (){
if(this.object === undefined) {
return this.object = Object.create({}); //Create your object
} else {
return this.object;
}
}
});
however i did notice some booboo's (Sorry always reminds me of Hook when i say that). First you do not need to alias the this keyword, were not working in an jQuery callback, even if we were you can bind your function etc.
Second and this is important. Your passing a $scope object into your service, this is very very bad. Not just for this reason but how can controllers share a single service object if it has a reference to a $scope? Your services should be a collection of single simple methods that have their input and output data. They work on that and continue. You can then chain them and pass them the specific data each method needs. They shouldn't be a monolithic object that has everything in hidden properties, think functional, a pipeline if you will.
I have a directive and now I want to send same data to other controller's methods and this controller is totally independent of this directive. this other controller is actually resides out the current directory.
How can I do this in angularjs?
Create an angular service and inject in both the controllers. Update a variable in that service from controller 1 and retrieve in controller 2. Something like this -
myApp.factory('myFactory', function () {
// declare and store the value in a local variable here
var prop = '';
return {
getProperty: function () {
return prop;
},
setProperty: function(value) {
prop = value;
}
};
});
function Ctrl1($scope, myFactory) {
myFactory.setProperty('myValue');
}
function Ctrl2($scope, myFactory) {
val = myFactory.getProperty();
}
An angular service is a Singleton, so it maintains the state throughout the code.
In angularjs there is an idea about directive scope.It lets you to use data for directive with 3 ways.
1) string #
2) biDirectional =
3) functional &
I think you have heard about these.This link maybe can help you.
https://docs.angularjs.org/api/ng/service/$compile#directive-definition-object
UPDATE 2:
I found out where the problem was coming from and I left out the important part.
I'm setting the property in the first controller INSIDE this
$rootScope.$on('anEvent', function (event, data) {
InjectedService.setToken(data.value);
})
But I can't grab it from outside that callback scope. The event that is listened for depends on an $http request so I'm guessing that is the problem. Are there any workarounds to this?
UPDATE:
The order of controllers are the other way around so that the code in secondController is actually being called first in my actual app. I have reordered them accordingly
Question:
I'm trying to grab the services specific property but when I try to grab the service property, I get undefined (using a getter function or not). But when I try to grab the full service, I get everything with the correct property and value.
main.js
angular.module('myApp', ['myModule', 'myServices'])
.controller('firstController', ['InjectedService', function(InjectedService) {
InjectedService.setProperty('Hello World')
}])
othermodule.js:
angular.module('myModule', [])
.controller('secondController', ['InjectedService',
function (InjectedService) {
console.log(InjectedService); // Full object with property == 'hello world'
console.log(InjectedService.property); // I get undefined
console.log(InjectedService.getProperty()); // I get undefined
// interesting to note:
InjectedService.setToken('A different string');
console.log(InjectedService.property); // I get 'A different string'
console.log(InjectedService); // Full object with property == 'Hello World' which was set in second controller
}])
services.js:
angular.module('myServices', function
.service('InjectedService', function(){
var Service = this;
Service.setProperty = function (value) {
Service.property = value;
}
Service.getProperty = function () {
return Service.property;
}
Service.unsetProperty = function () {
Service.property = null;
}
return Service;
})
It seems to me a scope problem, but the variable isn't a primitive type. Any suggestions?