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
Related
Im trying to catch the variables fromcontroller to use it in the view. but it wont work, but i do know that it exists ( debug on the picture below).
problem: I dont get anything in the view.
note: it might be cause the structure,
main structure is from: https://github.com/meanjs/mean
response:
nothing
my view:
<body class="ng-cloak" ng-controller="HeaderController as aux">
trying to get it to work:
<div class="cometchat_name">{{ varselmessage }} {{ aux.varselmessage }}</div>
function:
(function () {
'use strict';
angular
.module('core')
.controller('HeaderController', HeaderController);
HeaderController.$inject = ['$scope', '$state', 'Authentication', '$rootScope','Socket'];
function HeaderController($scope, $state, Authentication, $rootScope,Socket) {
var aux = this;
$scope.datatest = 200001;
$rootScope.datatest = 900;
$scope.varselmessage = 'varsel';
aux.varselmessage = 'varsel2';
$scope.notifications = [{text: " melding" , image : "kapring"}];
console.log("loaded , maybe possible4?");
}
}());
Problem is with the module, you are missing the dependency injection part [],
angular
.module('core',[])
.controller('HeaderController', HeaderController);
DEMO APP
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>
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.
How to synchronously bootstrap an angularjs app
I define a couple constant values on my app object. Some of these values need to be set via a call to a service and these calls need to complete before any of my controllers are instantiated.
In the example below, I define an array of values on an object named config. I need to set the value named PostIndexMenuID prior to any of my controllers being instantiated. How do I do that?
I have tried manually bootstrapping (removing ng-app from the html). I am not using routing.
Ideally I will not have to learn, download, install, configure, test, and maintain another framework to accomplish this.
(function()
{
angular.module('app', []);
var app = angular.module('app');
app.controller('controller', ['$scope', 'config', '$http', controller]);
app.service('menusService', ['$http', 'config', menusService]);
// Create config object. Some values are set in app.run
app.value('config', {
siteID: 100,
webRoot: '',
apiRoot: '/api',
imageRoot: '/Content/images',
PostIndexMenuID: 0
});
app.run(['$http', 'config','menusService', function ($http, config, menusService) {
menusService.GetMenuIDByName("PostIndex", function (data) {
config.PostIndexMenuID = data; // Need to complete this BEFORE GetPosts on the controller is called
});
}]);
function controller($scope, config, $http) {
var vm = this;
vm.Posts = 0;
function GetPosts() {
// In prod we call a service here get posts based on config.PostIndexMenuID
// for this example just return PostIndexMenuID.
vm.Posts = config.PostIndexMenuID;
};
GetPosts(); // need to delay calling this until AFTER PostIndexMenuID is set
};
function menusService($http, config) {
this.GetMenuIDByName = function (menuName, callBack) {
var uri = config.apiRoot + '/menu/GetMenuByName?menuName=' + menuName + '&siteID=' + config.siteID;
// use a timeout to simulate a slow service for this example and return a dummy value
var menuID = 99;
setTimeout(function () {
callBack(menuID);
}, 2000);
};
};
})()
// html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="app" >
<head>
<title></title>
</head>
<body >
<div ng-controller = "controller as vm">
<p>PostIndexMenuId is {{ vm.Posts }}</p>
</div>
<script src="Scripts/jquery-1.8.2.js"></script>
<script src="Scripts/angular.js"></script>
<script src="Scripts/angular-route.js"></script>
<script src="app/app.js"></script>
</body>
</html>
There is quite a nifty trick in Angular.js whereby you can defer the changing of a route until all promises have been resolved. You may have to restructure your application a little bit to cater for this approach, but I use it myself and it works like a treat!
$rootScope.$on('$routeChangeStart', function $routeChangeStart(event, next) {
// Extend the resolution of the route promise to wait for the user authentication
// process to determine if there's a valid session available.
next.resolve = angular.extend( next.resolve || {}, {
authenticating: api.isSession
});
});
By using the next.resolve you're extending Angular's sequence of promises that are resolved before a route change is considered a success. In the above case, as long as api.isSession returns a promise then everything will work wonderfully.
As soon as the api.isSession promise has been resolved, then the route change will succeed, and in your case, your controller will be loaded.
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 = {};