Data from AngularJS local storage service not rendering unless page refreshed - html

I am building a small AngularJS project and I have encountered a problem that I want to ask you guys about.
I am using angular-local-storage module to store some data coming from my API into the browser's local storage.
In one of my controllers I assign this data to a variable in the $scope object and try to render it in the view as follows:
controller:
angular.module('Dashboard')
.controller('DashboardController',
['$scope', '$rootScope', 'localStorageService',
function ($scope, $rootScope, localStorageService) {
$scope.userData = localStorageService.get('userData');
}]);
And the view:
<div class="row">
<h4>Welcome to your dashboard <strong>{{userData.personalUserInfo.name}}</strong>!</h4>
When I log into the app (which is when the data is fetched from API and stored in local store by key 'userData'), the view is incomplete, I get only "Welcome to your dashboard !" without the name there. When I go to the dev console and look at the localStorage of my browser, the entry "userData" is there, it is just not rendered.
Then when I hit F5 and refresh the page, the name appears.
Do you have any ideas why that is and what can be done to fix that?
Cheers!

You have to use $scope.$watch for this, like following:
$scope.$watch(function() {
return localStorageService.get('userData');
}, function(newVal, oldVal) {
if (newVal !== oldVal)
$scope.userData = newVal;
})
$scope.$watch, will execute second function each time return value of first function is changed.

Related

Can a service in Angularjs be used as tool for data transfer between controllers?

I have worked with this example to generate a data transfer between two different controllers in AngularJs, but it doesnt seem to work. Specifically I can change a variable of the service from the second controller and show it in its view, but the change will not show on the first controller. There, the variable has the original value which it has in the service.
I think it has something to do with the life cycle of the controller, and maybe I need to call the sencond controller first from the frist controller so the changes can be made? Also the code I am working with is different from the exmaple meaning I have a view for every controller and I am not using ng-controller in the html as in the exmaple.
Service This is my service. I want to overwrite itemId with value from a "foreign" controller, and than use it in my controller dashctrl which is connected to my dashboard.html.
var itemId = 10;
this.getData = function()
{
//console.log('in the Get Function');
return itemId;
};
this.setData = function(Id)
{
//console.log('in the Set Function');
itemId = Id;
};
Controller 1 This is the dashCtrl Controler where I read the variable itemId.
"Foreign" controller This is my foreign controller. I am trying to overwrite the variable from here so then I can use it in the dashboard.html which is only connected to dashCtrl, but its not working. This only shows the initial value of 10 of the service and nothing is overwritten. Now if I do the same with dashctrl the overwrite will work.
The view in html Screenshot from dashboard.html, calling the variable from dashCtrl.
Yes, it's possible and it was one the ways to handle or sync data between controllers in angularjs, we used services and factories.
I have a plnkr with an online demo here: https://plnkr.co/edit/ckV5P6nezNLpqvKK0vHm?preview
Basically, you need the service:
var app = angular.module('myApp', []);
app.service("myService", function() {
var c = 10;
this.theC = function () {
return c;
};
this.updateC = function () {
c++;
}
In the app Controller you will have:
app.controller('myCtrl1', [
'$scope',
'$rootScope',
'myService',
function($scope, $rootScope, myService) {
$scope.name = "Control 1";
$scope.service = myService;
}
]);
Finally in the template:
<div class="col-xs-6">
<h3>The Service</h3>
Shared Parameter: {{service.theC()}}
<br/>
<span class="btn btn-primary" ng-click="service.updateC()">Add to Shared</span>
</div>

How controllers and functions communicate between two separate files using .emit and how to tell controller hierarchy in AngularJS?

This is my first post on stack overflow so I am really green and really new with AngularJS and ASP.Net and having a lot of problems with $rootscope.$emit. From what I have read online $rootscopes are parent scopes so all values exposed there are visible to all controllers and templates and scopes are functions inside of controllers. It seems like you can "emit" up through the controller hierarchy a call to another controller by using $rootscope.$emit("Name of $rootscope.$on function name") the $rootscope.$on listens for that call and then does whatever is in its function. The thing I am having trouble with is when I do my
$rootscope.$emit("LoadPrintDetailsModal", {});
it never seems to reach
$rootscope.$on("LoadPrintDetailsModal", function(event,args) {}.
So the question is am I misunderstanding how $emit or how controller hierarchy works or is there a problem in my code?
I have already tried using emit and I hit the debugger in indexController.js file after a call from a button in my Index.cshtml file but then when I make the
$rootScope.$emit("LoadPrintDetailsModal", {});
it does not get picked up by my printableController.js file where
$rootScope.$emit("LoadPrintDetailsModal", function (event, args) {});
// (Index.cshtml) Button in Index.cshtml file that calls "LoadPrintModal" //function in indexController
<button type="button" data-toggle="modal" data-target="#dvPrintModal"
ng-click="LoadPrintModal()">
Print
</button>
// (indexController.js)scope.LoadPrintModal in indexController.js that tries
// to emit "LoadPrintDetails" to $rootscope.%on("LoadPrintDetailsModal",
// function (event, args) in printableçontroller.js
$scope.LoadPrintModal = function () {
debugger;
$rootScope.$emit("LoadPrintDetailsModal", {});
};
// (printableController.js) file where rootScope.on is located and is supposed to pick up the emit
app.controller('PrintableController', function ($scope, $rootScope) {
$rootScope.$on("LoadPrintDetailsModal", function (event, args) {
debugger;
$scope.printModal();
});
$scope.printModal = function () {
console.log("Hello World");
};
)};
The expected result should be a console log of hello world and we should hit the debugger in printableController.js file
Use $rootScope.$broadcast:
$rootScope.$broadcast("LoadPrintDetailsModal", {});
The $broadcast method dispatches events down the scope heirarchy.
The $emit method dispatches events up the heirarchy.
For more information, see
AngularJS Developer Guide - Scope Event Propagation
To capture broadcast events, use $scope.$on:
app.controller('PrintableController', function ($scope, $rootScope) {
̶$̶r̶o̶o̶t̶S̶c̶o̶p̶e̶.̶$̶o̶n̶(̶"̶L̶o̶a̶d̶P̶r̶i̶n̶t̶D̶e̶t̶a̶i̶l̶s̶M̶o̶d̶a̶l̶"̶,̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶e̶v̶e̶n̶t̶,̶ ̶a̶r̶g̶s̶)̶ ̶{̶
$scope.$on("LoadPrintDetailsModal", function (event, args) {
debugger;
$scope.printModal();
});
$scope.printModal = function () {
console.log("Hello World");
};
)};
From the Docs:
Only use .$broadcast(), .$emit() and .$on() for atomic events
Events that are relevant globally across the entire app (such as a user authenticating or the app closing). If you want events specific to modules, services or widgets you should consider Services, Directive Controllers, or 3rd Party Libs
Injecting services and calling methods directly is also useful for direct communication
Directives are able to directly communicate
For more information, seed
AngularJS Wiki - Best Practices
It's hard to know what is happening without:
seeing the hierarchy of the components. Is the emitting component is down in the hierarchy from the catching component. $emit is sending messages up. $browdcast is sending messages down.
Seeing how you inject $rootscope.
Regarding 2. $rootscope injection gives you the main $scope of the application. Doing $emit from it won't gives us anything as there are no $scopes that are above the $rootScope.
My guess you want to inject $scope which represent the specific scope in the hierarchy for that controller/component. Then $emiting will propagate upward to the catching controller/component properly.

How to create an angular form that uses session storage that can be called throughout the html pages

I want to create a form on an index page that can store data via session storage. I also want to make sure that whatever data(let's say name) ... is remembered and used throughout the site with angular. I have researched pieces of this process but I do not understand how to write it or really even what it's called.
Any help in the right direction would be useful as I am in the infant stages of all of this angular business. Let me know.
The service you want is angular-local-storage.
Just configure it in your app.js file:
localStorageServiceProvider
.setStorageType('sessionStorage');
And then use it in the controller that contains whatever data you want to remember. Here is an example of a controller that loads the session storage data on initialization, and saves it when a user fires $scope.doSearch through the UI. This should give you a good place to start.
(function () {
angular.module("pstat")
.controller("homeCtrl", homeCtrl);
homeCtrl.$inject = ['$log', 'dataService', 'localStorageService', '$http'];
function homeCtrl ($log, dataService, localStorageService, $http) { {
if (localStorageService.get("query")) { //Returns null for missing 'query' cookie
//Or store the results directly if they aren't too large
//Do something with your saved query on page load, probably get data
//Example:
dataService.getData(query)
.success( function (data) {})
.error( function (err) {})
}
$scope.doSearch = function (query) {
vm.token = localStorageService.set("query", query);
//Then actually do your search
}
})
}()

How to Query a JSON file using Angular/Ionic?

I'm trying to have Angular query a JSON file instead of using an http request in an Ionic project.
I'm working with the Ionic tutorial found here: https://ccoenraets.github.io/ionic-tutorial/index.html
I have gone through the entire tutorial and am "tinkering" which started with me wanting to change the data source from being an http request to a local JSON file and I've been partially successful.
All of the code I have in the project matches exactly what's seen in the tutorial with the following exception.
In the tutorial on "Module 4: Creating the Session Service," I changed this block seen in Step 3:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('http://localhost:5000/sessions/:sessionId');
});
To be:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json');
});
To create the JSON file I took the return value of the http request seen in the tutorial and pasted it into the file referenced in the code and it is valid JSON.
Now, when I run the project (in a desktop browser or emulator), I am able to see the list of Sessions that was read from the JSON as expected. However, when I click/tap one of the Sessions to see the detail, the UI appears but has no data. When using the original code that gets the data via http I can see the detail.
This is the controller in my code that matches the tutorial, which presumably is where the problem lies:
.controller('SessionCtrl', function($scope, $stateParams, Session) {
$scope.session = Session.get({sessionId: $stateParams.sessionId});
})
Here is the HTML for that view:
<ion-view view-title="Session">
<ion-content>
<div class="list card">
<div class="item">
<h3>{{session.time}}</h3>
<h2>{{session.title}}</h2>
<p>{{session.speaker}}</p>
</div>
<div class="item item-body">
<p>{{session.description}}</p>
</div>
<div class="item tabs tabs-secondary tabs-icon-left">
<a class="tab-item">
<i class="icon ion-thumbsup"></i>
Like
</a>
<a class="tab-item">
<i class="icon ion-chatbox"></i>
Comment
</a>
<a class="tab-item">
<i class="icon ion-share"></i>
Share
</a>
</div>
</div>
</ion-content>
</ion-view>
Here is the error in the console after clicking through to the Session detail view:
Error: [$resource:badcfg] get
http://errors.angularjs.org/1.3.13/$resource/badcfg?p0=object&p1=array
at REGEX_STRING_REGEXP (http://localhost:8100/lib/ionic/js/ionic.bundle.js:8762:12)
at d.module.provider.$get.e.(anonymous function).q.then.p.$resolved (http://localhost:8100/lib/ionic/js/angular/angular-resource.min.js:9:330)
at processQueue (http://localhost:8100/lib/ionic/js/ionic.bundle.js:21888:27)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:21904:27
at Scope.$get.Scope.$eval (http://localhost:8100/lib/ionic/js/ionic.bundle.js:23100:28)
at Scope.$get.Scope.$digest (http://localhost:8100/lib/ionic/js/ionic.bundle.js:22916:31)
at Scope.$get.Scope.$apply (http://localhost:8100/lib/ionic/js/ionic.bundle.js:23205:24)
at done (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18358:47)
at completeRequest (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18548:7)
at XMLHttpRequest.requestLoaded (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18489:9)
And here's the data where the Session list comes from and it's also the data I want to query:
[{"id":0,"title":"Introduction to Ionic","speaker":"CHRISTOPHE COENRAETS","time":"9:40am","room":"Ballroom A","description":"In this session, you'll learn how to build a native-like mobile application using the Ionic Framework, AngularJS, and Cordova."},{"id":1,"title":"AngularJS in 50 Minutes","speaker":"LISA SMITH","time":"10:10am","room":"Ballroom B","description":"In this session, you'll learn everything you need to know to start building next-gen JavaScript applications using AngularJS."},{"id":2,"title":"Contributing to Apache Cordova","speaker":"JOHN SMITH","time":"11:10am","room":"Ballroom A","description":"In this session, John will tell you all you need to know to start contributing to Apache Cordova and become an Open Source Rock Star."},{"id":3,"title":"Mobile Performance Techniques","speaker":"JESSICA WONG","time":"3:10Pm","room":"Ballroom B","description":"In this session, you will learn performance techniques to speed up your mobile application."},{"id":4,"title":"Building Modular Applications","speaker":"LAURA TAYLOR","time":"2:00pm","room":"Ballroom A","description":"Join Laura to learn different approaches to build modular JavaScript applications."}]
I can't seem to get my head wrapped around why changing the http request to a local file does not work for the query performed in 'SessionCtrl'.
What changes need to be made so the detail view will work?
UPDATE
Following the suggestion from #ErnestoRendon I think I have made progress.
I changed the factory to look like this:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json',{ }, {
getData: {method:'GET', isArray: false}
});
});
And the controller has been updated to look like this:
.controller('SessionCtrl', function($scope, $stateParams, Session) {
$scope.session = Session.getData({sessionId : $stateParams.sessionId});
console.log($stateParams.sessionId); // This DOES log the correct option selected from the list
})
When leaving isArray set to false I get the same object/array error when getData() is called. When I change isArray to "true" the error goes away but no data is returned to the UI. This is the error when setting that value to "false": http://errors.angularjs.org/1.3.13/$resource/badcfg?p0=object&p1=array
In either scenario (isArray being "true" or "false") the correct sessionId will log to the console from the controller.
So while things appear to be better when setting isArray to "true," I'm still not getting data into the UI.
Here's an example that loads data from a JSON file similar to what you describe.
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json',{ }, {
getData: {method:'GET', isArray: false}
});
});
Notice that isArray is set to false.

Angular-Translate: Translation does not show up on random browser refreshes

I have a separate language json file for each partial/controller. To avoid loading all the json files at once, I have added the addPart statement in the controller instead of the module config:
$translatePartialLoader.addPart('editName');
When I browse to the partial, I see that the json file is requested from the server only when needed. But when I keep refreshing the partial by clicking the function key F5, at random times, the json file is not requested from the server and the text displayed on the view is not translated. Not sure what I can do to fix this. Any help is greatly appreciated. Here is the code:
angular.module('pp')
.controller('informationList', [
'$scope', '$rootScope', '$location', '$translatePartialLoader', '$translate',
function($scope, $rootScope, $location, $translatePartialLoader, $translate) {
$translatePartialLoader.addPart('informationList');
$translate.refresh();
}
]);
Your issue sounds similar to mine.
This (called from app config) works:
angular.module('myApp').config(function ($translateProvider, $translatePartialLoaderProvider) {
$translateProvider.useLoader('$translatePartialLoader', {
'urlTemplate': '{part}-{lang}.json'
});
$translateProvider.preferredLanguage('EN');
$translatePartialLoaderProvider.addPart('headline');
$translatePartialLoaderProvider.addPart('languages');
});
This (called from controller) does not:
angular.module('myApp').controller('Ctrl', ['$scope', '$translate', '$translatePartialLoader', function ($scope, $translate, $translatePartialLoader) {
$translatePartialLoader.addPart('headline');
$translatePartialLoader.addPart('languages');
$translate.refresh();
}]);
Here is a plunker to demonstrate the problem.
http://plnkr.co/edit/sZC2XST8BMZcMCYbgtxt?p=preview
Could you just add a
$translateProvider.use('EN');
to the config - section just right below the "preferredLanguage('EN');" - line?
This should solve your problem.
It is in in fact currently needed to define that additional line - even though it might sound a bit like "duplication" :-).