I am working on an application were index page and inside that I am showing multiple views, In index nav bar I have to show notification count and User name which comes from 2 different controllers,
I am able to display the notification count and User name successfully, but the issue is the values are not changing dynamically.
We need to refresh the page for the new values.
What can I do in this situation can any one please guide me.
I'm guessing you're watching the value directly and not by some object wrapper. In this case javascript isn't actually updating the variable, but assigning a complete new one. Anything out of the function scope that updates the variable will never receive the new value.
The solution is simple; wrap the value in an object and share/inject that object.
angular.module('myApp')
.value('myPageState', {
notificationCount: 0
});
angular.module('myApp')
.controller('myController', function($scope, myPageState) {
$scope.myPageState = myPageState;
});
<div class="my-notification-thingy"> {{ myPageState.notificationCount }} </div>
You can achieve it by:
Maintain those values in rootScope so that you
will have the two way binding.
Making use of emit to notify the parent controller about value changes. This will work only if those two controllers are present in child elements.
In child controllers fire event on value update:
$scope.$emit('valueChanged', {value: val});
In parent controller receive event value:
$scope.$on('valueChanged', function(event, args) {
console.log(args.value);
});
Related
I make a query to Parse.com to receive a lot of objects and then display all the objects in a view.
I now want to be able to click on one of the objects, which should load a new page where I can edit them.
My questions is, how do I pass one of the objects from the main view to a detail view where I can edit it?
When I tried:
With route, passing the whole object, but this seems like bad practice, and the whole object is printed out in the status bar:
// Route
.when('/job/:object', {
<a href="#/job/{{job}}" style=" ">
By just passing the objectId, and when query the database to get the object by it's id once the detail view is loaded.
.when('/job/:objectId', {
<a href="#/job/{{job.id}}" style=" ">
// Get Object by its ID from Parse.com.
Save the whole array of objects in the $rootScope in order to access them from the new detail controller.
Thanks in advance
as SSH said you need to create one angular service which can hold the object , and then when you move from one view to another simply inject the service and access the object.
Here is how you should do this.
.service('holdobj',function(){
var myobj;
this.set= function(obj){
myobj = obj;
};
this.get= function(){
return myobj;
};
});
now in your controller
.controller(function(holdobj){
$scope.setObject = function(obj){
holdobj.set(obj);
}
});
And then when you want to get object simply call holdobj.get();
You should save an incoming object in a service, and then use that service across different controllers
As long as you are using a shared controller between views I think you could probably set a model before you change the view.
I don't know if there is a way to pass model between controllers when checking router otherwise, without going the old-fashioned way and passing an id to the object, where the second controller would look it up based on that.
In a view I have a link to choose a start location like below:
<input type="text" ng-model="placeStart" placeholder="place to start">
<input type="text" ng-model="weight" placeholder="goods weight">
and in the location page, I do choose a place, however, When I use $ionicHistory.goBack(), I could not pass the "place" back to the previous view. I also do not want to use state.go('previous view') to pass the "place", because in that way, I will lost the other input information in the previous view.
Here is :
$ionicHistory.backView().stateId;
don't ignore to include $ionicHistory on controller
There are three options which immediately come to mind. $rootScope, localStorage and using routing not goBack().
If you need the value from one view in another, and they're completely separate controllers etc then you need a way to pass them around.
You could create and then put the value into $rootScope.globals or similar.
You could store the value to localStorage before sending the user back.
You could redirect correctly to a route which allows the values to be included in the url and still show the provious page. For example the same route with and without values set, using - or 0 for not set depending on data type:
/an/example/route/-/-/
/an/example/route/0/0/
/an/example/route/123/456
Update:
There is actually a fourth way where you can send data between controllers using $broadcast and $on. The broadcast happens in the sending controller and the $on listens in the receiving controller(s) so you can send an update to values / an object etc. $on and $broadcast in angular
It depends on your situation but if you don't care to preserve state after a page reload which localStorage would be good for, but rather have the state be remembered just when you're going back (and not necessarily when you later navigate forward back into the view again) then I do this: I make a separate service, just an object that sticks around in which I can inject anywhere and store some variables. In Angular 1 this would be a service object.
angular.module('foo').factory("placeHelper", [
() => {
let _place = null;
class PlaceHelper {
set place(place){
_place = place;
}
get place(){
return _place;
}
reset(){
_place = null;
}
}
let helper = new PlaceHelper();
return helper;
}
]);
Then in your controller that you're going back to, you inject placeHelper and ask it for the place and restore your state via $scope.place = placeHelper.place and when in the UI for that controller someone selects a place, you just store it in the service, placeHelper.place = $scope.place.
I would use localStorage within the service if I wanted to keep the state around after a page refresh.
I don't like polluting $rootScope because it's harder to keep track after you start to have more than a few unrelated methods in there and your properties need to have longer names (or get grouped in objects anyway). It's better for maintainability to encapsulate and separate concerns.
Service variation:
The service could be an object literal instead of a class and you could directly set the properties instead of using methods if you wanted it to be a bit more simple.
angular.module('foo').factory("placeHelper", [
() => {
let helper = {
place: null,
reset(){
this.place = null;
}
};
return helper;
}
]);
I stumbled on the same problem recently. I ended up deciding to use $ionicHistory.currentView() and $ionicHistory.backView() (see documentation here). The former function returns an object associated to the current view, while the latter returns an object associated to the view you will go to after you call $ionicHistory.goBack().
Before calling $ionicHistory.goBack() on your location page you call $ionicHistory.backView() and define a new property to the returned object whose contents is the data you want to propagate to the other view.
On your other view, you change its '$ionicView.enter' event handler so it calls $ionicHistory.currentView(), which retrieves the object with the data you want.
Reaching out to you all for help yet again for AngularJS. I'm building a SPA where my Layout (master) Page is divided in to three section left navigation bar, center content, right item list bar. My right item list should be hidden when I load my home page, but should be visible in the remaining screens. I've created a $rootScope variable in the homeController and setting the value to 'true' based on the location path and using that variable in the template to set the value to ngHide. When I navigate to a different page as I'm using SPA, my right and left bars won't be loaded again, only my center content do which is a new view. While loading the new view in the controller that is sending the data to the new view's template I'm resetting the $rootScope variable that I've created in homeController to 'false', but my right bar is still not visible. I could see that ng-hidden class is still on though the interpollation has updated the value to 'true'. Any suggestions would be highly appreciated.
markup from layout page:
<aside class="right_bar" ng-hide="{{$root.show}}">
<div class="my-list"><span class="f3">My Cart</span><div class=""><span class="list-count">0</span></div></div><div class="list-item"><ul></ul></div>
</aside>
homeController code:
function getHomeConfigsCtrl($http, $location, $rootScope) {
$rootScope.show = false;
var loc = $location.path();
if (loc === '/Home/Index' || loc ==='')
{
$rootScope.show = true;
}
}
Categories Controller code: This is where I'm resetting my $rootScope variable's value
function getAllCategoryDetails($routeParams,$rootScope) {
$rootScope.show = false;
}
Two things about angular you need to know to make your presented code works:
You don't need to interpolate values using {{}} in ng directives, instead use ng-hide="showCart".
Assuming all your controllers are within the same angular application,
all scopes within the same application inherits from the same root,
i.e whatever you define on the $rootScope will be available to all
child scopes. To access the $rootScope.x from within any view in the application all you have to do is: {{x}} or in your case you're using it inside a directive you can do something like this:
<aside class="right_bar" ng-hide="showCart">
This will look for your current scope, if it has a showCart then it'll use it, otherwise it'll fetch the $rootScope.showCart
What I'm trying to build is a SPA containing multiple selects on one page, where each select has it's own model. Choosing different options in the select boxes may show/hide other fields on the page and modify data for other selects (load different sets). Finally options in two selects may change the url (so when page is loaded with a proper address, those two options will be preselected).
Now I'm wondering what'll be the best approach here.
First. Is it worth to switch to ui-router in this case ?
Second. I need to write a custom directive for this select, that will have the following functionality
load data collection
display data and remember selection
reload it's data collection when other select triggered it
reload data for other selects
Now I've written directives before but never anything this (I think) complex. That's why few questions come to my mind.
How can I bind different data to my directive ?
Should this be just a single massive complex directive or divide it to smaller parts (like one directive for showing closed select box and another one to show the list and so on) ?
How can I trigger event when data should be changed and listen to a similar event from another select. Via controller ?
Thanks in advance for all your help.
What I can suggest is keep it MVC. Here is one of the solution -
Create a controller to store model data (here $scope.selectOptions inside controller)
Pass this values to 'select directive' instance to display
Whenever user select the value in directive, pass that selected value to controller (lets say in controller $scope.selectedValue is holding that value)
In controller add $watch on $scope.selectedValue and in its callback call for different data set for another select option. (lets say storing that data set in $scope.anotherSelectOption )
Pass this $scope.anotherSelectOption to '2nd directive' instance
Whenever user select the value in 2nd directive, pass that selected value to controller (lets say in controller $scope.anotherSelectedValue is holding that value)
In controller add $watch on $scope.anotherSelectedValue and in its callback change url thing you want to do
Here's your HTML will look like -
<div ng-controller="MyCtrl">
<select-directive selection-option="selectOptions", selected-option="selectedValue"> </select-directive>
<select-directive selection-option="anotherSelectOptions", selected-option="anotherSelectedValue"> </select-directive>
</div>
Here's your controller, it will look something like this -
yourApp.controller('MyCtrl', function($scope) {
$scope.selectOptions = []; // add init objects for select
$scope.selectedValue = null;
$scope.$watch('selectedValue', function() {
// here load new values for $scope.anotherSelectOptions
$scope.anotherSelectOptions = [] // add init objects for select
$scope.anotherSelectedValue = null;
});
$scope.$watch('anotherSelectedValue', function() {
// here add code for change URL
});
});
Here's your directive scope is
yourApp.directive('selectDirective', function() {
return {
templateUrl: 'views/directives/select.html',
restrict: 'E',
scope: {
selectionOption: '=',
selectedOption: '='
}
};
});
I have a variable that will be used by one or more Controllers, changed by Services.
In that case, I've built a service that keeps this variable in memory, and share between the controllers.
The problem is: Every time that the variable changes, the variables in the controllers aren't updated in real time.
I create this Fiddle to help. http://jsfiddle.net/ncyVK/
--- Note that the {{countService}} or {{countFactory}} is never updated when I increment the value of count.
How can I bind the Service/Factory variable to $scope.variable in the Controller? What I'm doing wrong?
You can't bind variables. But you can bind variable accessors or objects which contain this variable. Here is fixed jsfiddle.
Basically you have to pass to the scope something, which can return/or holds current value. E.g.
Factory:
app.factory('testFactory', function(){
var countF = 1;
return {
getCount : function () {
return countF; //we need some way to access actual variable value
},
incrementCount:function(){
countF++;
return countF;
}
}
});
Controller:
function FactoryCtrl($scope, testService, testFactory)
{
$scope.countFactory = testFactory.getCount; //passing getter to the view
$scope.clickF = function () {
$scope.countF = testFactory.incrementCount();
};
}
View:
<div ng-controller="FactoryCtrl">
<!-- this is now updated, note how count factory is called -->
<p> This is my countFactory variable : {{countFactory()}}</p>
<p> This is my updated after click variable : {{countF}}</p>
<button ng-click="clickF()" >Factory ++ </button>
</div>
It's not good idea to bind any data from service,but if you need it anymore,I suggest you those following 2 ways.
1) Get that data not inside your service.Get Data inside you controller and you will not have any problem to bind it.
2) You can use AngularJs Events feature.You can even send data to through that event.
If you need more with examples here is the article which maybe can help you.
http://www.w3docs.com/snippets/angularjs/bind-value-between-service-and-controller-directive.html