AngularJS : How to get http data in differents controllers - angularjs

when I submit a form I have a controller that communicates with a service, which gets data from a server and return these data to the controller. Meanwhile, I change view with the form action. My problem is that I'd need the server response data in the second view (which has an another controller), but these are undefined. How can I fix this problem?
Ps. I'm sorry for my English
// code...
.state('app.search', {
url: "/search",
views: {
'menuContent' :{
templateUrl: "templates/search.html",
controller: 'SearchCtrl'
}
}
})
.state('app.result', {
url: "/result",
views: {
'menuContent' :{
templateUrl: "templates/result.html",
controller: "ResultCtrl",
}
}
})
// code...
<form name="search_form" ng-submit="searchLines()" action="#/app/result" novalidate>
// code...
</form>
.factory('Bus', function($http){
return{
get: function(callback){
$http({
method: "POST",
url: "someUrl",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: {someData from the form}
})
.success(function(data) {
callback(data);
})
.error(function(data, status, error) {
console.log(data, status, error);
});
}
}
});
.controller('SearchCtrl', function($scope, Bus){
$scope.searchLines = function(){
Bus.get(function(data){
$scope.company = data.company; // this is ok
});
};
})
.controller('ResultCtrl', function($scope, Bus){
// I'd like to have $scope.company here
})

Use a service for that.
Controllers shouldn't hold state.
Two controllers can communicate via a service(the service will hold the state as well).
Add a company variable on the Bus service and add a getter so other controllers can fetch the data from Bus.
Example:
HTML:
<div ng-app="app">
<div ng-controller="aCtrl">{{model.stateA}}</div>
<div ng-controller="bCtrl">{{model.stateB}}</div>
</div>
JS:
var app = angular.module('app', []);
app.service('myService', function ($q) {
var state = "12312";
this.getStateFromServer = function () {
return $q.when(state);
}
this.getRealState = function(){
return state;
};
});
app.controller('aCtrl', function ($scope, myService) {
myService.getStateFromServer().then(function (res) {
$scope.model = {
stateA: "A" + myService.getRealState()
};
});
});
app.controller('bCtrl', function ($scope, myService) {
$scope.model = {stateB: "B" + myService.getRealState()};
});
JSFIDDLE.

Related

Use service in multiple modules AngularJS

I have 2 modules that should be connected.
The main module, called mainPage has the second module, called router, injected. They are in separate files. I want to use my service called userPropagatorService in mainPage and in router.
This service should be used to get and set currently logged in user.
I tried to inject service to router module, but I get errors.
How can I achieve this?
mainPage file:
var app = angular.module('mainPage',['reg','router']);
//Returns a promise which generates our user.
app.factory('userLoginService',['$http',function ($http){
return{
loginService: function(username,password){
var info = {username:username, password:password}
var user={};
//Returning http request because of promises
return $http({
url: 'webapi/users/login',
method: 'POST',
data: info,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data:{username: info.username, password: info.password}
}).then(function (response)
{
user = response.data
return user;
});
}
}
}]);
app.service('userPropagatorService', function(){
return{
get:function(){
return this.u;
},
set:function(user){
this.u = user;
}
}
});
router file:
var r = angular.module('router',['ngRoute'])
.config(['$routeProvider', '$locationProvider','userPropagatorService',
function($routeProvider, $locationProvider, userPropagatorService) {
$locationProvider.html5Mode(true);
$routeProvider
.when("/home",{
templateUrl: "pages/MainPage.html",
controller:"homeController"
})
.when("/forums",{
templateUrl: "pages/forumsPage.html",
controller:"forumController"
})
.when("/topics",{
templateUrl: "pages/topicsPage.html",
controller:"topicsController"
})
.when("/comments",{
templateUrl: "pages/commentsPage.html",
controller:"commentsController"
})
.otherwise({
redirectTo:"/home"
});
}])
.controller("homeController",['$scope','$http',function($scope,$http){
/*$http({
url: "webapi/forums/all",
method:"GET"
})
.then(function(response){
console.log("YEA!");
console.log(response.data);
},
function(response){
console.log("NO:(");
})*/
$scope.username = "visitor!"
$scope.user = userPropagatorService.get();
if($scope.user != null){
$scope.username=$scope.user.username + "!";
}
}])
.controller("forumController",['$scope','$http',function($scope,$http){
$scope.username = "visitor!"
}])
.controller("commentsController",['$scope','$http',function($scope,$http){
$scope.username = "visitor!"
}]);
If you want to use the userLoginService in the router module, it needs to be broken out of the main app.
var app = angular.module('mainPage',['reg','router']);
angular.module("services",[])
.factory('userLoginService',['$http',function ($http){
return{
//Service code here
};
}]);
Then add it as a dependency in the router module:
var r = angular.module('router',['ngRoute','services'])
You cant inject Service "userPropagatorService" in config block.
Make it a provider with $method and return function from there .
ang.provider('userPropagatorService', function(){
return{
get:function(){
console.log("in get");
},
set:function(user){
},
$get: function(){
return {
meth1: function(){
}
}
}
}
});
ang.config(function(userPropagatorServiceProvider){
console.log(userPropagatorServiceProvider.meth1())
})

Server calls for every View Redirect(Change) in AngularJS

I have an usual AngularJS Controller:
controllers.UController = function ($scope, uFactory) {
$scope.data1 = uFactory.getDataUsingAjax1();
$scope.data2 = uFactory.getDataUsingAjax2();
$scope.data3 = uFactory.getDataUsingAjax3();
...
}
The mentioned fields (data1 - data3) gets populated using Ajax call.
I also have several Views.
When I run my app the first time, I can see all the 3 Ajax calls in order to populate data1-data3.
But every time I redirect to another View, I can see that this population starts again and again.
In my understanding it's not really a SPA architecture or it's a bad SPA.
Is this how it should work or I am missing something?
Here are the details:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/',
{
controller: 'UController',
templateUrl: '/Partial/View1.html'
})
.when('/View2',
{
controller: 'UController',
templateUrl: '/Partial/View2.html'
})
.otherwise({ redirectTo: '/View3' });
}]);
myApp.factory('uFactory', function () {
var factory = {};
data1 = [];
data2 = [];
factory.getAjaxData1 = function () {
$.ajax({
url: url,
type: 'GET',
contentType: "application/json",
async: false,
success: function (result) {
data1= result;
}
});
return data1;
}
factory.getAjaxData2 = function () {
$.ajax({
url: url,
type: 'GET',
contentType: "application/json",
async: false,
success: function (result) {
data2= result;
}
});
return data2;
}
}
var controllers = {};
controllers.uController = function ($scope, $location, uFactory) {
$scope.data1 = uFactory.getAjaxData1();
$scope.data2 = uFactory.getAjaxData2();
}
Redirection is done by href link:
a href="#/View1"Do it/a

Cannot set property from angularjs service

I am trying to set value in html page from angularjs controller.
I am getting value from web api in service but I have issue that I am always getting error:
TypeError: Cannot set property 'messageFromServer' of undefined
But I can't figure what am I doing wrong here. What am I missing?
On the html part I have:
<div ng-app="myApp" ng-controller="AngularController">
<p>{{messageFromServer}}</p>
</div>
In the controller I have:
var app = angular.module('myApp', []);
app.controller('AngularController', ['$scope', 'messageService', function ($scope, messageService) {
$scope.messageFromServer = "When I set it here it works!"
messageService.getMessage();
}]);
app.service('messageService', ['$http', function ($http) {
this.getMessage = function ($scope) {
return $http({
method: "GET",
url: "api/GetMessage",
headers: { 'Content-Type': 'application/json' }
}).success(function (data) {
$scope.messageFromServer = data;
console.log(data);
}).error(function (data) {
console.log(data);
})
};
}]);
Basically the problem is, you missed to $scope object to the service getMessage method. But this is not a good approach to go with. As service is singleton object, it shouldn't manipulate scope directly by passing $scope to it. Rather than make it as generic as possible and do return data from there.
Instead return promise/data from a service and then assign data to the scope from the controller .then function.
app.service('messageService', ['$http', function ($http) {
this.getMessage = function () {
return $http({
method: "GET",
url: "api/GetMessage",
headers: { 'Content-Type': 'application/json' }
}).then(function (response) {
//you could have do some data validation here
//on the basis of that data could be returned to the consumer method
//consumer method will have access only to the data of the request
//other information about request is hidden to consumer method like headers, status, etc.
console.log(response.data);
return response.data;
}, function (error) {
return error;
})
};
}]);
Controller
app.controller('AngularController', ['$scope', 'messageService',
function ($scope, messageService) {
$scope.messageFromServer = "When I set it here it works!"
messageService.getMessage().then(function(data){
$scope.messageFromServer = data;
});
}
]);
Don't use $scope in your service, just return the promise from $http.
var app = angular.module('myApp', []);
app.service('messageService', ['$http', function ($http) {
this.getMessage = function () {
return $http({
method: "GET",
url: "api/GetMessage",
headers: { 'Content-Type': 'application/json' }
});
};
}]);
app.controller('AngularController', ['$scope', 'messageService', function ($scope, messageService) {
messageService.getMessage().then(function(data) {
$scope.messageFromServer = data;
});
}]);
In this example you can unwrap the promise in your controller, or even better you can use the router to resolve the promise and have it injected into your controller.
app.config(function($routeProvider) {
$routeProvider.when('/',{
controller: 'AngularController',
templateUrl: 'views/view.html',
resolve: {
message: function(messageService) {
return messageService.getMessage();
}
}
});
});
Then in your AngularController, you'll have an unwrapped promise:
app.controller('AngularController', ['$scope', 'message', function ($scope, message) {
$scope.messageFromServer = message;
}]);

Pass a request header to uriTemplate in AngularJS

I have this Angular code:
.state('UserTables', {
url: '/Tables',
resolve: {
auth: function resolveAuthentication(SessionService) {
return SessionService.isUser();
}
},
views: {
"containerMain": {
templateUrl: 'Views/Tables',
controller: TableController
},
}
})
And would like to pass some request header to the templateUrl call.
Anyone done something like that?
Basically I have a REST service that can generate the view I need depending on 1 header and some property's. Property's are no problem but I have no clue how to make a call to the service and wait for the result.
Tried:
views: {
"containerMain": {
template: function (SessionService, $http, $q) {
console.log('template');
var resp = SessionService.getTable($http, $q, 'Generate/Table?objectId=WfObject');
var r = '';
resp.then(function (result) {
r = result;
console.log('resp:', r);
});
console.log('r:',r);
return r;
}
I created working plunker here
To load template with custom headers, we can call do it like this (check the state 'UserTables' in the plunker):
views: {
"containerMain": {
//templateUrl: 'Views/Tables',
templateProvider: ['$http',
function ($http) {
var tplRequest = {
method: 'GET',
url: 'Generate/Table?objectId=WfObject',
headers: {
'MyHeaderKey': 'MyHeaderValue'
},
}
return $http(tplRequest)
.then(function(response) {
console.log('loaded with custom headers')
var tpl = response.data;
return tpl;
}
);
}],
controller: 'TableController'
},
}
In case, we want (and can) cache the template, we can do it like this (check the state 'UserTablesWithCache'):
views: {
"containerMain": {
//templateUrl: 'Views/Tables',
templateProvider: ['$http', '$templateCache',
function ($http, $templateCache) {
var templateName = 'Generate/Table?objectId=WfObject';
var tpl = $templateCache.get(templateName)
if(tpl){
console.log('returning from cache');
return tpl;
}
var tplRequest = {
method: 'GET',
url: templateName,
headers: {
'MyHeaderKey': 'MyHeaderValue'
},
}
return $http(tplRequest)
.then(function(response) {
console.log('loaded, placing into cache');
var tpl = response.data;
$templateCache.put(templateName, tpl)
return tpl;
}
);
}],
controller: 'TableController'
},
}
And if we would not need headers, and we could cache, it is really very easy, as documented here:
Trying to Dynamically set a templateUrl in controller based on constant
Drafted version could be: (no custom headers but effective loading and caching)
templateProvider: ['$templateRequest', function(CONFIG, $templateRequest) {
var templateName = 'Generate/Table?objectId=WfObject';
return $templateRequest(templateName);
}],
templateUrl property can also take function as value. So you can add dynamic properties to the templateUrl via there.
templateUrl : function(stateParams) {
// before returning the URL, add additional properties and send
// stateParamsargument object refers to $stateParams and you can access any url params from there.
return 'Views/Tables';
}

UI-router won't resolve promise

I'm not quite sure what I'm doing wrong, but it seems that my profile doesn't resolve by the time we get to the MainCtrl. The user however does, resolve. Am I, perhaps not fetching the profile information properly in the Auth Service?
Router:
angular.module('app')
.config(function ($stateProvide) {
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'app/main/main',
controller: 'MainCtrl',
resolve: {
user: function (Auth) {
return Auth.getUser();
},
profile: function (user) {
return Auth.getProfile();
}
}
});
});
Controller:
angular.module('app')
.controller('MainCtrl', function ($scope, user, profile) {
$scope.user = user;
$scope.profile = profile; <- DOESNT RESOLVE
});
Auth Service:
angular.module('app')
.factory('Auth', function ($firebaseSimpleLogin, $firebase, FBURL) {
var ref = new Firebase(FBURL);
var auth = $firebaseSimpleLogin(ref);
var Auth = {
user: {},
getUser: function () {
return auth.$getCurrentUser();
},
getProfile: function(uid) {
return $firebase(ref.child('users').child(uid)).$asObject();
}
};
return Auth;
});
Something like
auth.$getCurrentUser()
returns a promise so you need a
.then(function(user) {
event before your callback complete
In your case you may just resolve on the then, something like
Auth.getUser().then(function(user){ return user; });
Also $asObject() needs $loaded() for it's promise
var obj = $firebase(ref).$asObject();
obj.$loaded()
.then(function(data) {})
Try this structure for your promises:
var fetchSomething = function (action, params) {
var promise = $http({
method: 'POST',
url: 'someurl to the firebase',
data: params,
headers: {
'Access-Control-Allow-Origin': true,
'Content-Type': 'application/json'
}
}).success(function (data, status, headers, config) {
return data;
});
return promise;
};

Resources