view is not updated in AngularJS - angularjs

I have an issue when I try to display data.
I send my form and update my database (it works great, backend is ok)
I use a button on the page to return to homepage
The view of the homepage is not updated, always the same values.
(It seems that there is only the template that loads, not with queries)
I need to click on the button refresh of the browser to see new values.
After the 'hard' refresh, the view is updated.
Why do I need to completely refresh the page ?
Here is my code
JS :
My service GenericService
(I created this service because I use this in several controllers)
myApp.factory('GenericService', function ($http, $q, MyFunctions) {
var data = {};
function getDataIfNeeded(action) {
action = action || 'default';
if (data[action] !== undefined) {
return $q.when(data[action]);
}
return $http({
url: "php/functions.php",
method: "GET",
params: {
action: action,
dummy: MyFunctions.randomString(7)
}
}).then(function(response) {
data[action] = response.data;
return data[action];
});
}
return {
getData: getDataIfNeeded
};
});
The call of the service
myApp.controller('listCtrl', ['$scope', '$http', '$rootScope', '$location', 'GenericService',
function ($scope, $http, $rootScope, $location, GenericService) {
GenericService.getData("get_projects").then(function (data) {
$scope.projects = data;
});
GenericService.getData("get_projects_draft").then(function (data) {
$scope.projects_in_draft = data;
});
}]);
HTML :
<div ng-controller="listCtrl">
<div ng-repeat="project in projects">
<span>{{ project.nom }}</span>
</div>
<div ng-repeat="project_draft in projects_in_draft">
<span>{{ project_draft.nom }}</span>
</div>
</div>

Your service GenericService fetch the data from the server only "if needed", which means if the local data variable isn't empty. Naturally, without reloading the service and after a form submission, the data will be out-of-sync! So you have two choices:
If the server is creating additional data, i.e. possesses data that AngularJS don't have after the form submission, you need to do another request in order to fetch the new data. Just empty the local data variable.
Else, if the server is just saving the data in a database for instance, and doesn't perform any other operation with an impact on what is shown on your page, you don't have to do an other request, since you already know what you sent to the server! Just update the local data variable.

Related

How to Query Data From Firebase Into AngularJS

Hope some of you can provide me with some suggestions on how to Query Data From Firebase into my HTML Page.
Controller
.controller('cloudCtrl', ['$scope', '$stateParams', '$firebaseArray' ,// $stateParams.parameterName
function ($scope, $stateParams, $firebaseArray) {
var ref2 = firebase.database().ref().child("info");
var sync = $firebaseArray(ref2);
console.log(sync.toString());
sync.orderBychild('name').endAt(3).on('child_added', function(snap){
console.log('added', snap.val())
})
}])
HTML5 File
<div ng-controller="cloudCtrl">
<button ng-click="Load()">Load User</button>
</div>
Since you are using angularfire, you can do it this way:
$scope.load = function() {
$scope.result = firebase.database().ref().child("info").orderByChild('name').endAt(3);
}
Be careful concerning the camelCase on orderByChild.
You only need to watch the data if you want an event to occur when a child is added. For example, send a notification when a new message is available. Otherwise the database works in realtime, so if you modify a the name in info (directly in the firebase console) it will be available and updated in your scope.
There is one other way to do this which might come in handy while you're preparing your app:
$firebaseArray(yourRef).$loaded().then(function(result) {
$scope.result = result;
})
This will handle the promise while you're fetching the data. That might be useful if you want to show a loader while fetching the data which you would show before that function and hide once it is done.
Hope it helps !

Data from service arent updated

I'm very new to AngularJS and programming aswell, so it can be easy question for you but I'm struggling with it for plenty of hours and can't get my thinking straight.
So, my goal is simple, to have facebook login on my app (webpage), I'm using Ciul angular-facebook module, this actually works but not in the way I want it. When user loggs I want to show his name and photo, but now I have to manually reload page, then it shows, until then it won't. Also I'm storing logged user into localStorage (works ok).
The problem is that after logging in the data aren't updated. In my html code I tried to call them from controller or service, but both had old data, and I don't know how to update it without reloading the page. The most interesting part is when I try it with simple variable and it works like a charm.
Here is my Service
app.factory('mainService', ['$window', '$location', '$route', '$filter', 'Facebook', function (win, $location, $route, $filter, Facebook) {
var scope = {
fbLogin: false,
fbUid: 0,
fbAccessToken: 0,
vkLogin: false
};
var user = {};
if(localStorage.getItem('user') != null) {
user = JSON.parse(localStorage.getItem('user'));
} else {
user = null;
}
return {
scope : scope,
user : user,
fbLogin : function () {
Facebook.login(function (response) {
scope.fbLogin = response.status;
scope.fbAccessToken = response.authResponse.accessToken;
scope.Uid = response.authResponse.userID;
Facebook.api('/me?fields=id,name,email,picture', function (response) {
localStorage.setItem('user', JSON.stringify(response));
});
});
console.log('setting user');
user = JSON.parse(localStorage.getItem('user'));
},
fbLogout : function () {
Facebook.logout(function (response) {
});
user = null;
localStorage.removeItem('user');
},
removeAuth : function () {
Facebook.api({
method: 'Auth.revokeAuthorization'
}, function (response) {
Facebook.getLoginStatus(function (response) {
scope.fbLogin = response.status;
});
});
}
};
}]);
Here is my Controller
app.controller('IndexController', ['$scope', '$location', '$http', 'mainService', function ($scope, $location, $http, mainService) {
$scope.ms = mainService;
$scope.user = mainService.user;
$http({
method: 'GET',
url: 'backend/api/v1/getItems.php',
headers: { "Content-Type": 'text/json; charset="utf-8"' }
})
.success(function(data, status) {
//alert("status is : "+status);
if(status === 200) {
$scope.items = data;
}
})
.error(function(data, status) {
$scope.items = [];
});
}]);
Calling login function < li >< a href="#/" ng-click="ms.fbLogin()">Login using Facebook
Calling data in html {{user.name}} or {{ms.user.name}}
Well, the same problem is also with logging out.
Hey so it's hard for me to say this is the exact problem but from the looks of it everything you have so far is actually pretty good.
There's only one problem I spot and it just boils down to understanding objects are bound to variables by reference. If you're not sure what that means I would say do some research on that first since it's a fundamental part of javascript.
What seems to be the problem here is that you are setting 'user' to an empty object in your service. In your controller you are then assigning $scope.user to that same object empty.
However in your login function you are assigning user to the new JSON from the storage. First, this should also be inside the success callback, right after you set the localstorage.
I'm not familiar with that module but I'm going to assume that those are async functions. Therefore you're grabbing that local storage data before it's even been set.
Also, by setting 'user' to a new object you have updated it's value in the service but not in the controller.
Because it's bound by reference, 'user' in the service now points to a new object, while $scope.user is still pointing to that original empty object.
To solve this problem you can do two things:
Handle the callback differently so that you reassign $scope.user to the new data.
Or you can take advantage of object reference.
You can keep most of your code the same, but in your service, instead of assigning the data to 'user', assign it to a property on user.
Facebook.api('/me?fields=id,name,email,picture', function (response) {
localStorage.setItem('user', JSON.stringify(response));
user.data = response;
});
Since both the service and the controller are referencing the same object, you will have access to that new data property on $scope.user.
HTML:
<span>{{user.data.name}}</span>

Setting up dynamic $http.get request (Angular)

I want to know how to dynamically change an $http call so that the $http request URL differs based on the element that is clicked in an ng-repeat list. But I'm stuck.
Currently, I have an ng-repeat set up on my index page:
<div ng-repeat="team in nt.getStandings">
<h2>{{team.team_name}}</h2>
<p>Team ID = {{team.team_id}}</p>
</div>
The variable getStandings is taken from an API via an $http call. Like so:
In StandingsService
return $http.get(
'http://api.com/standings/1005?Authorization=xxxx'
)
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
And then StandingsService is attached to the getStandings variable in my controller.
"1005" is a property which calls a specific array, in this case a particular sporting competition, from an array of competitions.
So, on my index page I'm using ng-repeat to list all teams within that competition.
As you can see on the html above, I have linked each team so that it dynamically generates a URL which appends the team_id to the end, which using $routeParams I define as the variable whichTeam.
Team Details Page
<h1>Dynamic Team ID = {{whichTeam}}</h1>
This works fine, the team ID is generated dynamically according the team that is clicked.
Just like 'StandingsService' above, I have another service called 'TeamService' which makes an $http request to pull team data. Currently though it is set up statically to make a call to one individual team - I want to make the service take in the whichTeam variable so that the call changes depending on which team was clicked.
This is the static team $http request (I've broken the URL apart and concatenated to make it clearer):
return $http.get(
'http://api.com/team/' + '16110' + '?Authorization=xxxx'
)
I want the 16110 part, which refers to ONE team, to be a the whichTeam variable, allowing it to pull in the correct individual team data, but I don't know how to write this (or indeed if it's possible).
I hope I've been clear - happy to clarify further if needed. Thanks in advance.
Make a factory:
app.factory("DataService", ["$http", function($http) {
return {
getTeamDetailsById: function(teamId) {
return $http.get('path/to/api' + teamId + '?Auth=xxxx')
}
};
}]);
Use it in a controller:
app.controller("MainCtrl", ["$scope", "DataService", function($scope, DataService) {
$scope.teamDetails = {};
$scope.getTeamDetailsById = function(event, teamId) {
//prevent click navigation
event.preventDefault();
//call factory service
DataService.getTeamDetailsById(teamId).then(function(response) {
//success callback
$scope.teamDetails = response.data;
}, function(response) {
//an error has occurred
});
}
}]);
In the ng-repeat element:
<div ng-repeat="team in teams">
<a href ng-click="getTeamDetailsById($event, team.team_id)">{{team.team_name}}</a>
</div>
The above assumes you have only one state and are storing in only one controller. If you want to use different states usving $stateProvider, then you'd have to use parameters, by making use of ui-sref and passing in team Id.
If indeed you are using $states and parameters, do this:
<a href ng-click="goToState($event, team.team_id)">{{ team.team_name }}</a>
$scope.goToState = function(e, teamId) {
$state.go("teamDetailsState", { "teamId": teamId });
}

Make response from API call accessible from all controllers - angular

I have a controller that takes the user input and post's it to my API and captures the response which happens to be the user data. That's great however I need to access the user data on the dashboard which has a different controller. I can't figure out how to abstract the API call into a service and fetch the response from the dashboard controller. Is there an easier way? The login functionality works perfect however the res.data.user appears inaccessible. My question is how do I make the response accessible from a diffefrent controller?
Controller (signup):
angular.module('app').controller('Signup', function ($scope, $http, toastr, $location, $auth) {
// Submit request to Sails.
$http.post('/api/user/email', {
email: $scope.signupForm.email.toLowerCase(),
password: $scope.signupForm.password
})
.then(function onSuccess(res){
$auth.setToken(res.data.token)
$location.path('/dashboard')
$scope.user = res.data.user;
})
})
HTML (dashboard):
<div class="container" ng-show="isAuthenticated()" ng-controller="Dashboard">
<p>License: {{user.license}}</p>
</div>
Have a factory or service that stores user data to pass around. Inject it in the original
.factory('storeData', function () {
var userData = {}; //it's empty, thats ok
function dataAll () {
return userData;
};
return dataAll;
}
.controller('Signup', function ($scope, $http, toastr, $location, $auth, ***storeData***) {
//remove *** obviously
var importedData = storeData();
// or storeData.dataAll() for some reason OP said this didn't work but it works in my code
$http.post('/api/user/email', {
email: $scope.signupForm.email.toLowerCase(),
password: $scope.signupForm.password
})
.then(function onSuccess(res){
$auth.setToken(res.data.token)
$location.path('/dashboard')
will modify factory object that was returned to contain res.data.user
instead of blank. javascript does not make copies, but instead links
back to the original factory object. So changes take place on the
factory object.
importedData = res.data.user
$scope.user = res.data.user;
})
})
new controller example
.controller('test', function ($scope, storeData) {
console.log(storeData() + 'see if data shows up');
}

How does one scope an Angularjs factory service to return unique data to a specific controller?

I'm new to angularjs and have been attempting to use the angularui modules to build an accordion. For each accordion header I have a nested tag to which calls my service factory. The service factory returns data according to the id and updates my inner accordion content however it updates it for all of the accordion headers. So in other words, clicking on an accordion header will load the same content for all accordion divs. I would like it to return only to the clicked header. I believe I need more help in understanding the scope of my factory service. So my question is if someone can help me understand how to get my service factory to only update it's caller.
my html:
<accordion close-others="false">
<accordion-group ng-repeat="dept in departments">
<accordion-heading>
<span ng-controller="DeptHeaderCtrl" ng-click="loadEmps(dept.DeptID)">
{{dept.DepartmentName}} ({{dept.DepartmentShortName}})
</span>
</accordion-heading>
<div ng-controller="departmentList">
<div ng-repeat="emp in deptemps">
{{emp.Name_First}}
</div>
</div>
</accordion-group>
angularjs factory service code:
app.factory('DeptFactory', function ($http, $rootScope) {
var sharedDeptEmpList = {};
sharedDeptEmpList.EmpList = '';
sharedDeptEmpList.fetchDeptEmps = function (deptid) {
var dept = { "userid": userid, "deptid": deptid };
$http({ method: 'POST', url: 'api/Fetch/DeptEmployees/', data: dept }).
success(function (data, status, headers, config) {
EmpList = data;
sharedDeptEmpList.broadCastEmpList();
}).
error(function (data, status, headers, config) {
alert('error');
});
};
sharedDeptEmpList.broadCastEmpList = function () {
alert('broadcasting');
$rootScope.$broadcast('handleBroadcast');
};
return sharedDeptEmpList;
});
Angularjs controller that receives broadcast:
app.controller('departmentList', function ($scope, $http, DeptFactory) {
$scope.init = function (p_userid) {
userid = p_userid;
};
$scope.$on('handleBroadcast', function () {
alert('broadcast received');
$scope.deptemps = EmpList;
});
});
Each directive is just some javascript that associates a DOM node with a given scope. The same way you think of the DOM tree, you can think of a "scope tree". On the other hand, services are just singleton objects that can be injected and used anywhere. They have no implicit relationship to the DOM/scope tree.
By injecting $rootScope into your DeptFactory, you are giving it access to the entire scope tree. When you call $broadcast(), you are sending an event throughout the entire tree, beginning at the root, and then propagating outwards to all of the leaf scopes.
I don't see enough of your code to completely understand what's happening, but I'm guessing that you're seeing all of your accordion divs change because they are all receiving your $broadcasted event, and reacting to it the same way. I would suggest you $broadcast some sort of ID value to identify which div you are trying to change. Then, when you handle this event in each accordion, check the ID against the accordion's ID to see it should change or not.
Does this help?

Resources