Angular controller not updating view without page refresh - angularjs

I have a problem with my login routine using passport js, express and angular. While the login as such works smoothly I want to use the window object to store the current logged in user for authentication purposes.
After username and password are validated using passport I am using the successRedirect, that triggers index.render
// Set up the 'signin' routes
app.route('/signin')
.post(passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/signin',
failureFlash: true
}));
exports.render = function(req, res) {
// Use the 'response' object to render the 'index' view with a 'title' and a stringified 'user' properties
console.log('Window Object:',req.user);
res.render('index', {
title: 'Test',
user: JSON.stringify(req.user)
});
};
Once I login to the application the window.user object turns from null to the following (index.ejs).
<!-- Render AngularJS views -->
<header data-ng-include="'header.client.view.html'"></header>
<section data-ui-view></section>
<div id="contactform" data-ng-include="'contactform.client.view.html'"></div>
<footer data-ng-include="'footer.client.view.html'"></footer>
<!-- Render the user object -->
<script type="text/javascript">
window.user = {"_id":"55cb06e523d7d6680d14c215","provider":"local","firstName":"Karl","lastName":"Karl","email":"karl.karl#test.com","__v":0,"created":"2015-08-12T08:42:13.807Z","active":true,"fullName":"Karl Karl","id":"55cb06e523d7d6680d14c215"};
</script>
Now I have been very unsuccessful in retrieving the window.user object in my angular controller as it is seen as null as long as I haven't done a page refresh.
<!-- Render the user object -->
<script type="text/javascript">
window.user = null;
</script>
So the question is now, how do I retrieve the window object, as I want to update my angular view accordingly, showing in the header that the user has been logged in?

I think you are meant to use a Angular service to store variables that are to be shared amongst controllers. Sorry, I guess I'm trying to nudge you out of your preferred solution to use the Window object to store state.
Some sample code from a common services module
//var com_serv = angular.module('common.services')
com_serv.service('sharedProperties', function () {
var property = 'Not yet set';
return {
getProperty: function () {
return property;
},
setProperty: function (value) {
property = value;
}
};
});
Related SO questions
how-can-i-pass-variables-between-controllers
how-to-pass-dynamic-data-from-one-module-controller-to-another-module-controller

Related

Angular $http fails to return coherent cache

I have a problem where a page has two components but only one of them is fully rendered.
The problem seem to be related to $http. I have a angular project where I need to construct a page based on RESTful API. The pages are such that I can expect multiple requests for the same data. At the moment, the set of requests are not behaving correctly.
For the sake of the argument (and also because it is a use case), the following page makes the same request twice.
game.html:
<html ng-app="prvdApp">
<head>
<meta charset="utf-8">
<base href="/">
<title>Providence</title>
<script src="/js/angular-1.6.2.js"></script>
<script src="/data-access/data-access.service.js"></script>
<script src="/score-info/score-info.component.js"></script>
<script src="/js/game.js"></script>
</head>
<body>
<div ng-controller="gameController">
<score-info game-id="8000"></score-info>
<score-info game-id="8000"></score-info>
</div>
</body>
game.js:
angular.module('prvdApp', [
'scoreInfo',
'drivesInfo' ]);
angular.
module('prvdApp').
controller('gameController', function() {
});
score-info.component.js:
angular.module('scoreInfo', [
'dataAccess'
]);
angular.
module('scoreInfo').
component('scoreInfo', {
templateUrl : '/score-info/score-info.template.html',
controller : function ScoreInfoController(dataAccess) {
self = this;
self.$onInit = function() {
dataAccess.game(self.gameId).then(function(game) {
self.game = game;
});
}
},
bindings : {
gameId : '<'
}
});
score-info.template.html:
<div>
Data available: {{ $ctrl.game != undefined }}
</div>
data-access.component.js:
angular.module('dataAccess', []);
angular.
module('dataAccess').
service('dataAccess',
function DataAccessService($http, $q) {
self = this;
self.game = function(game_id) {
var url = '/api/game/' + game_id;
return $http.get(url, { cache: true}).then(function(response) {
return response.data;
});
}
});
The behaviour is as follows:
The page renders with the content:
Data available: false
Data available: false
After some hundreds of milliseconds the $http -request finishes, the page is updated to the following state where only the latter component is updated.
Data available: false
Data available: true
It should be noted that the behaviour is the same even if the two components are of different types with different controllers, etc.

angularjs templates not hiding div from route

It's two page user registeration process depending on the role the second page could be different but the first page will always remain the same. what I want I that user can go forward and backwards on both screens with persistent data. I trying a static page at start and then hide it and add the second template from route.
This is my angular app controller.
app.controller('addlandlordController' , function($scope , $http , $route ,API_URL , $routeParams , uploadService ){
$scope.API_URL = API_URL;
$scope.landVisible = true;
$scope.IsVisible = true;
if( $routeParams.test)
{
scope.$apply(function () {
$scope.IsVisible = false;
});
alert( $routeParams.test);
}
$scope.adduser = function($route){
var data = $.param({
fName: $scope.firstName,
lName: $scope.lastName,
role: 'landlord',
email: $scope.email,
linkId: $scope.linkId,
password: $scope.password,
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
$http.post(API_URL + 'user' , data , config)
.then(
function(response){
//$scope.IsVisible = false;
//alert('success');
},
function(response){
// failure callback
alert('fail');
}
);
}
});
I have a div in html like this,.
<div id="content" class="container1" ng-controller='addlandlordController' >
<div ng-show = "IsVisible">
And following is my route in config,.
app.config(function($routeProvider){
$routeProvider.when('/landlord' , {
templateUrl : 'template/addlandlord.html',
controller : 'addlandlordController',
resolve: {
test: function ($route) { $route.current.params.test = true; }
}
})
});
What I want is that when the user click on the following button.
Create an Account</button>
On click that button #/landlord will be added to the url and the route config code will run and add the other template in ng-view which is happening. Now next step is to hide the old div above in such a way that when user go back one sten only the previous code should show and when user goes again into the next screen only the next template should be visible and mean while data should remain same for the both views.
Issues I am facing is
Css is for template view is missing although the css files are already in the commen header. But appears when a place css in the style within template.
if I hide the first div in the response of adduser then if user go back it still hidden. it doesn't appears unless I refresh the page.
But if went to hide it through route config the value turn false but div never hides.
Please check this
scope.$apply(function () {
$scope.IsVisible = false;
});
You are using $apply on scope, but not in $scope.
And $applyAsync is preferable method to trigger digest without risking of error "$digest already in progress"
$applyAsync example:
$element.on('click', ()=>{
$scope.model.testValue = 'I have been updated not from angular circle';
$scope.$applyAsync();
});
Link to the docs
Nice article to read

backbonejs demo case can't work well with localstorage added in stack snippet

I am trying to use the stack snippet tool to embed live demo case into my post. But I find when I add localstorage function into the demo case, it can't work well.
So I simplified my question to the basic backbone case, to emphasis the localstorage issue as above.
And if I remove the localstorage flow, the demo can run through very well, but if localstorage added, then it can't work well. The error message from console said
Failed to read the 'localStorage' property from 'Window': The document is sandboxed and lacks the 'allow-same-origin' flag.
Any idea?
// A simple case
var Daymodel = Backbone.Model.extend({
defaults : {
day: 1,
}
});
var DayCollection = Backbone.Collection.extend({
model: Daymodel,
localStorage: new Backbone.LocalStorage("test-simple")
});
// The view for each day panel
var DayView = Backbone.View.extend({
tagName:"div",
template: _.template( $('#eachday-template').html() ),
initialize: function() {
this.listenTo(this.model, "change", this.render);
},
render: function(){
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
// The view for the entire application
var AppView = Backbone.View.extend({
el: $('#todoapp'),
events: {
"click #add-firebase":"addToLocalhost"
},
initialize: function() {
this.daylist = this.$("#container"); // the daylist to append to
this.listenTo(this.collection, 'add', this.addOne);
this.collection.fetch();
},
addOne: function(todo) {
var view = new DayView({model:todo});
this.daylist.append(view.render().el);
},
addToLocalhost: function(){
this.collection.create({
day : this.collection.length + 1,
});
}
});
// Create a function to kick off our BackboneFire app
function init() {
// The data we are syncing from our remote Firebase database
var collection = new DayCollection();
var app = new AppView({ collection: collection });
}
// When the document is ready, call the init function
$(function() {
init();
});
<div id="todoapp">
<div id="container"></div>
<button id="add-firebase">Add to Localstorage</button>
</div>
<script type="text/template" id="eachday-template">
<h3 class="which-day"> day <%= day %></h3>
<ul id="todo-list"></ul>
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone-localstorage.js/1.1.16/backbone.localStorage-min.js">
</script>
The answer is in the error message you're getting: "The document is sandboxed". You can't mess with the localStorage as it's a restricted feature for all sandboxed iframe documents unless the restriction is specifically lifted.
If you look at the page source, you'll see the iframe and the sandbox attribute options.
<iframe name="d62428c9-4eba-3156-6ef7-8815d959a281"
sandbox="allow-modals allow-scripts"
class="snippet-box-edit" frameborder="0">
See Play safely in sandboxed IFrames for more details.
The framed document is loaded into a unique origin, which means that
all same-origin checks will fail; unique origins match no other
origins ever, not even themselves. Among other impacts, this means
that the document has no access to data stored in any origin's cookies
or any other storage mechanisms (DOM storage, Indexed DB, etc.).
[...]
With the exception of plugins, each of these restrictions can be
lifted by adding a flag to the sandbox attribute’s value. Sandboxed
documents can never run plugins, as plugins are unsandboxed native
code, but everything else is fair game:
allow-forms allows form submission.
allow-popups allows popups (window.open(), showModalDialog(), target="_blank", etc.).
allow-pointer-lock allows (surprise!) pointer lock.
allow-same-origin allows the document to maintain its origin; pages loaded from https://example.com/ will retain access to that
origin's data.
allow-scripts allows JavaScript execution, and also allows features to trigger automatically (as they'd be trivial to implement
via JavaScript).
allow-top-navigation allows the document to break out of the frame by navigating the top-level window.
For allow-modals, Add allow-modals to the sandbox of Stack Snippets gives more details:
Chrome blocks modal dialogs such as alert, confirm and prompt in
sandboxed iframes unless allow-modals is set. This behavior became the
default as of Chrome 46 and Opera 34.

Scope refuses to update

for some reason unknown to me, I can't get the controller scope to update the view,
even though apply is running and the scope itself has been updated.
I know that because when I console.log(data) I see its been updated.
userList directive should assign data.activeUser property on controller's scope.
its working, but the view is not updating accordingly
Link to the demo: http://jsbin.com/mojemiki/6/edit
var app = angular.module('app', []);
app.controller('myCtrl', function ($scope) {
$scope.data = {
users : [{
name : 'bob'
},{
name : 'koko'
}],
activeUser : {}
};
$scope.selectUser = function (user) {
// console is showing user data
console.log(user);
$scope.data.activeUser = user;
console.log($scope.data.activeUser);
// data.activeUser has been updated, but the view is not. why is that?
// $scope.$apply() - is not helping
// because its aleady running
};
});
app.directive('userList', function () {
return {
scope : {
users : '=',
onSelect : '&'
},
template : '<h3>in directive scope</h3>' +
'<button ng-repeat="u in users" ng-click="onSelect({ user : u })">Set Active User: {{u.name}}</button>' +
'<br/><code>{{users}}</code>'
};
});
The problem is that you are including Angular.js twice (version 1.2.1 from Cloudflare CDN and version 1.2.14 from Google CDN) and this is causing some kind of conflict. Remove one of them and it will work.
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js"></script>
Here is your fiddle.

Show user info after login AngularJS

I am building an AngularJS application and I would like to show user info in the header of the page when user is logged in. Something like "Welcome,{{username}}".
I have created a SessionHandler service where I keep the information about the user.
module Shared{
export class SessionHandler implements ISessionHandler {
loggedUser: string;
SetLoggedUser(user: string) {
this.loggedUser = user;
}
GetLoggedUser(): string {
return this.loggedUser;
}
}
}
angular.module("MainApp").service("SessionHandler", Shared.SessionHandler);
I have tried creating a directive
angular.module("MainApp").directive("myheader", function () {
return {
restrict: "E",
templateUrl: "/app/shared/partials/header.html",
controller: function ($scope, SessionHandler: Shared.ISessionHandler) {
$scope.LoggedUser = function () {
SessionHandler.GetLoggedUser();
}
}
}
});
my header template is simple..
<span>{{LoggedUser()}}</span>
my main app module looks like this
angular.module("MainApp", ['ui.bootstrap','Login', 'Module2'])
...
.run(($rootScope: ng.IRootScopeService, $location: ng.ILocationService, SessionHandler: Shared.ISessionHandler) => {
$rootScope.$on("$routeChangeStart", (event, next, current) => {
if (!SessionHandler.IsUserLoggedIn()) {
$location.path("/login");
}
if (next.templateUrl == "/app/module/login/partials/login.html") {
SessionHandler.ClearSession();
return;
}
});
});
and my login Controller which is in Login module calls a method on the server and after successful login sets logged user by calling SetLoggedUser() method on SessionHandler.
my index
<html data-ng-app="MainApp">
<head>
</head>
<body>
<div class="container-fluid">
<myheader></myheader>
<div data-ng-view=""></div>
</div>
</body>
</html>
When I start my application logged user is empty so I only see Welcome (I will fix this later) but after I login I am redirected to another partial view but nothing changes in the header.
I am obviously missing something but I just can't figure out what.
Thank you.
In your header directive you are missing the dependency or you can say reference to your SessionHandler service.
Can you try to add that and check what happens next..

Resources