I am using Angular 1.5 and I call a web api (/api/users/self) to get information about the current authenticated user (name, id, ...) so I can use that information on my Angular controllers.
(function () {
"use strict";
angular.module("app").controller("MessageInboxController", MessageInboxController);
MessageInboxController.$inject = ["$timeout", "messageService", "userService"];
function MessageInboxController($timeout, messageService, userService) {
var vm = this;
}
})();
On message controller I will call the UserService to get current user info.
So in many controllers I need to do this ...
Is there a way to call the UserAPI once and share this info with all controllers?
What is your advice?
Create a service to store your data in and inject it into your controllers:
var myApp = angular.module('myApp', []);
myApp.factory('DataRepo', function() {
var data = {
name: 'Superhero'
};
return {
data: data
};
});
myApp.controller('MyCtrl1', function($scope, DataRepo) {
$scope.name = DataRepo.data.name;
});
myApp.controller('MyCtrl2', function($scope, DataRepo) {
$scope.DataRepo = DataRepo;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl1">
Hello, {{name}}!
</div>
<div ng-controller="MyCtrl2">
Hello, {{DataRepo.data.name}}!
</div>
</div>
The best way to do this would be to use an authentication service and keeping the user object in cache.
If you are sending the user object alongwith the Main page when it gets rendered from the web-app:
// Authentication service for user variables
angular.module('users').factory('Authentication', ['$window',
function($window) {
var auth = {
// if you are sending the user object when rendering the page
user: $window.user
};
return auth;
}
]);
You can inject this service in all your controllers and get to the user through Authentication.user.
Or you can use a call to the web service from your angular service.
In your service if the user object is null call to the web-service if its not null return the user.
Related
I've been searching around for hours, but I couldn't find a solution. I'm trying to retrieve data from a separate json-file in my AngularJS application. Using the $http I do get the data I want.
However, I want to get specific data from that file at in multiple places. In the service I want to define some functions that controllers can call to retrieve the data (that the service got using $http).
Now the problem is that when I return the all the data to the controller directly, or try to use it later in the service, the assigned variables are undefined.
I try to use controller-as syntax, so I do not want to use $scope. However every solution I've found suggests using $scope. This code now logs
f {$$state: {...}}.
Code of the service:
theApp.service('SettingsService', function($http) {
this.dataVar = $http.get('../settings.json')
.then(function(response) {
return response;
});
});
Code of the controller:
theApp.controller('SomeController', ['SettingsService', function(SettingsService) {
console.log(SettingsService.dataVar);
}]);
UPDATE:
https://jsfiddle.net/md954y0a/
what about calling your service at start-up module then passing to submodules through a service that loads the same instance
html:
<div ng-app='myApp' ng-controller="myctrl">
{{parent}}
<div ng-app='myApp1' ng-controller="myctrl1">
{{myApp1data}}
</div>
</div>
js:
angular.module('myApp', ['myApp1']).controller('myctrl', ['$scope', 'API', function($scope, API) {
$scope.parent = API.getData();
}]).service('API', function($q) {
var object = null;
this.getData = function() {
object = {
obj1: "DATA1",
obj2: "DATA2"
};
return object;
}
});
angular.module('myApp1', []).controller('myctrl1', ['$scope', 'API', function($scope, API) {
$scope.myApp1data = API.getData().obj1
}]);
My index.html looks like this:
<body ng-controller="ExternalCtrl">
<div ng-include=" 'header.html' "></div>
<div ng-view></div>
<div ng-include=" 'footer.html' "></div>
<!-- all scripts, angular modules, directives, services etc.. -->
</body>
External controller wrap entire webpage, so I should have access to ExternalCtrl variables wherever in my app for example in headerCtrl which is controller of included header.html file.
I need this because in externalCtrl I get the value from localStorage (which are stored there after success login user) and if its present set a _authentication.isAuth = true; so I can develop my page with ng-if="_authentication.isAuth" for logged in users and ng-if="!_authentication.isAuth" for not logged in.
My externalCtrl code is:
'use strict';
app.controller('ExternalCtrl', ['$scope', 'localStorageService',
function($scope, localStorageService) {
var _authentication = {};
var _authentication = {
isAuth: false
};
var authData = localStorageService.get('authorization');
if(authData) {
_authentication.isAuth = true;
console.log(_authentication.isAuth);
}
}
]);
At this point console.log works correctly and log true if it is true or false if its false obviously.
After that I want to check if I have access to that variable in headerCtrl which is controller of included header.html as I mentioned above. So in this controller i add line:
console.log(_authentication.isAuth);
Which cause following error:
ReferenceError: _authentication is not defined
Why?
Is it correct way of doing this?
It is because _authentication is defined inside the controller. It is not available globally. You can define it on $scope or $rootScope.
function($scope,$rootScope, localStorageService) {
$scope._authentication = {};
$scope._authentication = {
isAuth: false
};
var authData = localStorageService.get('authorization');
if(authData) {
$scope._authentication.isAuth = true;
console.log($scope._authentication.isAuth);
}
}
]);
For more info: AngularJS access parent scope from child controller
I am trying to consume my ASP.NET Web API using AngularJs. The problem is that i want to pass optional parameters to the url based on the user input(2 Html Text Boxes) but i don't know how.
This is my ASP.NET Web API Controller
[Route("api/JobShow/{keyword}/{location}")]
public class JobShowController : ApiController
{
[HttpGet]
public PageResult<sp_JobSearch_Result> Get(ODataQueryOptions<sp_JobSearch_Result> options, string keyword = null, string location = null)
{
ODataQuerySettings settings = new ODataQuerySettings()
{
PageSize = 20
};
JobWindow obj = new JobWindow();
IQueryable results = options.ApplyTo(obj.showJobs(keyword, location).AsQueryable(), settings);
return new PageResult<sp_JobSearch_Result>(
results as IEnumerable<sp_JobSearch_Result>,
Request.GetNextPageLink(),
Request.GetInlineCount());
}
}
And this is my AngularJS controller
angular.module('JobSearch.SiteController', []).controller('JobSearchCtrl', ['$scope', '$http', function ($scope, $http) {
$http.get('/api/JobShow').success(function (data) {
$scope.model = data;
});
}]);
Example of the url then would be .../api/JobShow/Java/Toronto. Thank you all.
You can try ngResource !
You first need to include ng-resource
<script src="angular.js">
<script src="angular-resource.js">
You can get it via Bower or CDN, or whichever way you got AngularJS.
HTML:
<body ng-app="MyApp">
<div ng-controller="MyCtrl">
<label>Keyword: <input type="text" ng-model="keyword" /></label>
<label>Location: <input type="text" ng-model="location" /></label>
<button ng-click="getJobShowPage(keyword, location)">Search</button>
</div>
</body>
Controller:
angular
.module('MyApp', ['ngResource']) // Include the ngResource module here
.controller('MyCtrl', ['$scope', '$resource', function($scope, $resource){
// Create the $resource
var JobShowPage = $resource('/api/JobShow/:keyword/:location', {keyword: "#keyword", location: "#location"})
// Make a scope function to use the resource properly
$scope.getJobShowPage = function(keyword, location) {
var parameters = {};
if (keyword) {
parameters["keyword"] = keyword;
if (location) {
parameters["location"] = location;
}
}
return JobShowPage.get(parameters);
};
}]);
Input/Outputs:
When the user enters nothing and clicks 'Search', the HTTP request would be /api/JobShow
If only the keyword is entered, the HTTP request would be /api/JobShow/{{keyword}}
If both the keyword and location is entered, the HTTP request would be /api/JobShow/{{keyword}}/{{location}}
If only the location is entered (no keyword), the HTTP request would be the vanilla one /api/JobShow
You can consume the return value of the $resource query like a promise:
JobShowPage.get(parameters).$promise.then(function(response){
// Do Stuff
$scope.model = response.data;
});
by callbacks:
JobShowPage.get(parameters, function(err, response){
// Do Stuff
$scope.model = response.data;
});
Or auto unwrap it:
// This works, but it's asynchronous
// Useful if consuming directly from the Angular Template
$scope.model = JobShowPage.get(parameters);
Based on your code, I'm going to assume you have 2 textboxes and a search button, and when the search button is pressed, you want to call your GET endpoint. For this scenario, what you'll want to do is bind the textbox inputs to your scope and bind the search button using ng-click to a function in your scope that will call your endpoint. It might look something like this:
controller
angular.module('JobSearch.SiteController', [])
.controller('JobSearchCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.getResults= getResults;
function getResults() {
$http.get('/api/JobShow/' + $scope.keyword + '/' + $scope.location).success(function (data) {
$scope.model = data;
});
}
}]);
html
<div ng-controller="JobSearchCtrl">
<input type="text" ng-model="keyword">
<input type="text" ng-model="location">
<button type="button" ng-click="getResults()">Search</button>
</div>
So I am able to show the username via mongoose passport-local within my successful redirect:
app.get('/profile', isLoggedIn, function (req, res) {
res.render('profile.html', {
user: req.user
});
console.log(req.user.local.username) //correct username for the session
});
...and then use it to display within profile.html:
<p><%= user.local.username %></p>
...yet when trying to display the same within my ng-view:
<div ng-view ng-class="slide" class="slider"></div>
...via my route example.html template:
<p>welcome <%= user.local.username %></p>
..it is displayed as seen: not the correct username...
Is it not possible to include this information within an ngView? Is there a solution to include this info within my template? I have attempted to setup a factory with $http:
angular.module('userService', [])
.factory('Users', function($http) {
return {
get : function() {
return $http.get('/profile');
}
}
});
...but it was returning the entire html, so not a correct solution.
Any guidance is as always welcomed and appreciated, so thanks in advance!
Edit in response:
Getting the value and routing it isnt really the issue. The issue is just getting it to display correctly within the ngView.
heres my updated code:
Rules.get()
.success(function (data) {
$scope.rules = data;
console.log('Rules.get()');
console.log(data);
Users.get()
.success(function (username) {
Users.username = username;
console.log('Users.get()')
console.log(username)
});
});
...and...
angular.module('userService', [])
.factory('Users', function ($http) {
return {
get: function () {
console.log('userService')
return $http.get('/profile/user');
}
}
});
...which returns from:
app.get('/profile/user', function (req, res) {
console.log('profile/user')
console.log(req.user.local.username)
res.json(req.user.local.username);
});
This gives me the same and correct username, but alas what do I call it to get it to display in the ngView? If placed outside of the actual ngView div it displays fine.
From the above {{username}} {{rules.username}} = nothing. What should be the name of the service param within the ngView template (which I am assuming is an entirely new $scope)?
Question is possible duplicate of Angular and Express routing?
You could include ejs templating (like <%= value %>) inside ng-views (see link above), but here are three other options.
Many people pass server data to Angular and let Angular template their views (e.g. in the MEAN stack). This would mean you wouldn't need to have ejs templating in your angular partials. Here are three ways to pass data from your server to Angular (Credit to this blog post: http://mircozeiss.com/how-to-pass-javascript-variables-from-a-server-to-angular/):
1. the MEAN method
The first is what is used in the MEAN stack. You could send all of the data your Angular app needs in the wrapper around your ng-view:
<!-- head -->
<!-- body -->
<!-- ng-view element -->
<script type="text/javascript">window.user = <%- user %>;</script>
<!-- rest of js -->
<!-- /body -->
This way the data can be accessed by your Angular app via a provider like so:
angular.module('myApp')
.factory('UserData', [
function() {
return {
user: window.user
};
}
]);
2. using $http and an api
The second is providing this data via a restful api and requesting the data via a provider using $http or $resource:
angular.module('myApp')
.factory('UserData', [
function($http) {
$http.get('/userAPI').success(function(data){
return data;
});
}
]);
3. Using ng-init
Finally you could use server-side templating inside an ng-init.
<div ng-init="user = <%- data %>"></div>
This would put the data on $scope.user for your Angular app to use.
So here was my solution for anyone else that may be searching:
users.js:
angular.module('userService', [])
.factory('Users', function ($http) {
return {
get: function () {
console.log('userService')
return $http.get('/profile/user');
}
}
});
route.js
$scope.username = {};
.controller('cntrl', function ($scope, Users) {
getCurrentUser(Users, $scope);
})
function getCurrentUser(Users, $scope) {
Users.get()
.success(function (username) {
$scope.username = username.user;
});
}
service.js:
app.get('/profile/user', function (req, res) {
console.log('profile/user')
console.log(req.user.local.username)
res.jsonp({ user:req.user.local.username});
});
then within html (within any ngView template):
<span class="username">{{username}}</span>
the key being:
$scope.username = {};
I want to pass a variable between controllers with a service. Here is the service to pass the variable (in this case a song id):
'use strict';
angular.module('PortalApp')
.service('ActionbarService', ['$window', function ActionbarService(window) {
var song;
return {
getSong: function () {
return song;
},
setSong: function(value) {
song = value;
}
};
}]);
Here is the relevant part of the controller I am setting the song from:
$scope.actionbarSetSong = function(song_id) {
ActionbarService.setSong(song_id);
}
and here is the controller I am getting the song id from:
'use strict';
angular.module('PortalApp')
.controller('ActionbarCtrl', function ($scope, MediaService, ActionbarService, $location, $routeParams, AudioPlayerAPI) {
$scope.song_id = ActionbarService.getSong();
$scope.openPlaylistModal = function (song_id) {
$("#addToPlaylist").modal('show');
}
});
It is being set in the service because when I do getSong in my view it worked (I forget where), but then when I try to set it in my 2nd controller it doesn't work. Here's the relevant part of my view for reference:
<div class="cell action-bar" ng-click="actionbarSetSong(song.id);" ng-repeat="song in media.data">
Some Stuff
</div>
Mmm.. service returns new ActionbarService. You probably want to use factory, or change your getters/setters to this.get & this.set.
Also, avoid polluting the $rootScope; whenever you want to share data between controllers, use a service.