Why isn't {{ username }} variable (in example below) updated when I'm navigating using in-page links? The variable is only set on initial page load (equal to Anonymous) and isn't updated no more, why is that? Code i plain and simple (http://jsbin.com/OTApeYI/1/):
<!doctype html>
<html lang="en" ng-app="examp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"> </script>
</head>
<body ng-controller="ExampleCtrl">
Home, Admin
Your user name is: {{ username }}
<script>
angular.module('examp', ['examp.controllers']).
config(function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/:username', {controller: 'ExampleCtrl'});
$routeProvider.otherwise({redirectTo: '/'});
});
angular.module('examp.controllers', [])
.controller('ExampleCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
$scope.username = $routeParams.username ? $routeParams.username : "Anonymous";
}]);
</script>
</body>
</html>
First, I think you need the ngView directive to activate routing. Second, ExampleCtrl is only created once and you are setting $scope.username to the current value at that time. $routeParams.username is a simple string, you might as well set $scope.username = '' You can however store the $routeParams object on your scope and bind to the username property (SAMPLE). I also disabled html5 or I don't think it works with jsbin.
<div ng-view></div>
<p>Your user name is: {{ username }}</p>
<p>params.username is: {{ params.username }}</p>
<p>eventusername is: {{ eventusername }}</p>
<p>JSON:</p><pre>{{ params|json }}</pre>
And in your controller:
$scope.params = $routeParams;
Another option would be to look for route change events and handle them:
$scope.$on("$routeChangeStart", function(event, next, current) {
$scope.eventusername = next.params.username;
});
Because you're always using the 'ExampleCtrl' controller, you're only ever reading the $routeParams once. The $routeParams object is only created the one time that the controller is created. It doesn't update dynamically. So even though your route may have changed from say /macadamia to /macadamia123, the $routeParams object is still the same as it was when the controller was created for your /macadamia route (so $routeParams.username still equals '/macadamia'). You need to reload the controller in order to read the $routeParams again.
I've wanted the $routeParams object to be dynamic for a long time, but unfortunately angular's $routeProvider doesn't work that way.
Related
I am working on a app that switches between different screens. Each screen collect data from the user by means of user selecting a button and clicking on it or selecting a radio button. There will be at least 5-6 screens. i need ideas on how and where to store the data collected and what's the best way to move between different screens: switch what is displayed inside a div on the page or go to an entirely different page. The data on each screen is coming from the different database tables.
So far I have one screen done - it pulls data from the database(via Web API call) and based on the data pulled, displays a different image in the hyperlink.
What I want to do is capture which hyperlink is clicked by the user and store that value somewhere(a location that will persist until all data is collected and stored in the database) and then move on to the next screen. I am sort of stuck here and need some help and ideas.
here is what i got so far:
UI for screen 1:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Types</title>
<script src="../../Scripts/angular.js"></script>
<script src="TypesCtrl.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="myController">
<h3>Select a type</h3>
<br />
<table>
<tr>
<td ng-repeat="Type in Types">
<img src="Images/type1.png" ng-show="Type.TypeId=='1'" />
<img src="Images/type2.png" ng-show="Type.TypeId=='2'" />
<img src="Images/type3.png" ng-show="Type.TypeId=='3'" />
<img src="Images/type4.png" ng-show="Type.TypeId=='4'" />
</td>
</tr>
</table>
</div>
</body>
</html>
and here is my angular controller:
(function () {
angular.module("myApp", []).controller("myController", TypeCtrlFunction);
TypeCtrlFunction.$inject = ["$scope", "$http"];
function TypeCtrlFunction($scope, $http) {
$http.get('http://localhost:49358/api/myAPI/GetTypes').
then(function (result) {
$scope.DeviceTypes = result.data;
});
};
})();
I'd appreciate some help to get me moving forward
You can share data between the different states/controllers either by setting up a service or by using rootScope. Typically it is better practice to use a service. Then you can change views using uiRouter. An example for setting up states:
app.config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/main");
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'main.html'
})
.state('main.mainstuff', {
url: '/mainstuff',
templateUrl: 'mainstuff.html'
})
.state('main.secondstuff', {
url: '/secondstuff',
templateUrl: 'secondstuff.html'
});
}]);
Here is a plunker showing how implement using nested states. This example uses rootScope but you should consider using a service as AndyHasIt mentioned.
You coude use ui-routing for swithing between different views. As for storing data there are two ways i would do it. One is using services to store values or you could also use local storage or cookies in browser for the same
To share data between controllers, use a service:
app = angular.module('MyApp', []);
app.service('SharedDataService', function() {
return {
someVar: 'hello'
}
})
app.controller('Controller1', function(SharedDataService, $scope) {
$scope.value1 = SharedDataService.someVar;
})
app.controller('Controller2', function(SharedDataService, $scope) {
$scope.value1 = SharedDataService.someVar; //The same value
})
To load different pages within the same page I suggest you use ngRoute or uiRouter
I have a JavaScript web app where I used AngularJS to ease things up, but now I bumped into a little problem.
I want to change viewfrom an ng-controller. I use $location.path to do this, but sadly, nothing happens. If I check the $location object, the path will be changed correctly, but the view isn't changing.
I have an ng-view in my Home.html. This is the config I wrote for it:
<html ng-app="app">
...
<body>
<div id="navigation-menu" ng-controller="NavigatorController">
<a class="menulink" ng-class="{ active: isActive('/labels')}" href="#page2">Page2</a>
<a class="menulink" ng-class="{ active: isActive('/labels')}" href="#page3">Page3</a>
</div>
<div ng-view></div>
</body>
</html>
This is the config I made for the $routeProvider which works flawlessly when used in the menusystem
myApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'Page1.html',
controller: 'Page1Controller'
})
.when('/page2', {
templateUrl: 'Page2.html',
controller: 'Page2Controller'
})
.when('/page3', {
templateUrl: 'Page3.html',
controller: 'Page3Controller'
});
});
Upon opening the app I want to show the Page1.html in the ng-view, so that's sorted with the '/' url thing, I guess.
The problem is, that from every other controller, I want to be able to get back to the Page1.html.
I tried making an event in every other controller, like this:
$scope.NavigateBack = function() {
$location.path('/');
}
It's not working, sadly. I don't get any error messages though... I tried it with different addresses in the path, like "/page2", but nothing worked.
What am I doing wrong, that the view isn't changing and the page isn't navigating?
I recommend use
$window.location = "#/"
but don't forgot to inject $window to your controller
Define behaviour in the Page2Controller, for example:
$scope.goBack = function(){
$location.path("#/");
}
And add some button inside of Page2.html:
<button ng-click="goBack()">Return</button>
You might also need to change your navigation links href attribute to #/page2 and #/page3
I am beginner in angular js
HTML
<div ng-app="myapp">
<div ng-controller="maincontrol">
<div ng-show="!vis">show</div>
<div ng-show="vis">hide</div>
</div>
<div ng-view></div>
</div>
JS
var app = angular.module('myapp', ['ngRoute'])
app.controller('maincontrol', function ($scope) {
$scope.vis = true;
$scope.fun = function () {
if ($scope.user == "home" && $scope.pass == "home") {
console.log($scope.user, $scope.pass);
$scope.vis = false;
}
}
})
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'home.html'
})
.when('/contact', {
templateUrl: 'contact.html'
})
});
and also i have two html pages like
home.html
<div ng-controller="maincontrol">
<input ng-model="user"/>
<input ng-model="pass"/>
<div ng-click="fun()">
click
</div>
</div>
contact.html
<div>
contact
</div>
my expectation is after entering home into user and pass. if i click 'click' i need to show 'show' label instead of 'hide'. pls help me.
Each controller has its own scope, when you wrote $scope.vis=false on fun(), you actually created a new variable on maincontroler1 scope. If you expected this variable to affect the view which is binded to maincontroler scope, it won't happen.
I suggest 2 options:
You can use one controller for entire app (If you use same controller in two tags it will still create a new scope although it is the same controller), this way the fun() method that was called from the first view will change the boolean in the single controller and will affect the second view. Please note when you use ng-view you will have to get the variable from the parent.
So I used this code:
$parent.user
$parent.pass
Create this working plunker for you.
Share the vis boolean between 2 controllers using a service. You can
use this post for this option.
You can also use reach parent controller scope from child controller, that can be done if ng-view will be nested in the outer controller. You can use this post for option 3.
I worked through the tutorial on the AngularJS website and I noticed that in at step 7, they change how a controller is introduced into the application. Initially, they use a directive:
<body ng-controller="PhoneListCtrl">
...
</body>
However, it later gets changed to use a controller attribute as part of an ng-route.
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
/* rest of routes here */
Here's the git diff where the change is made. Is there a difference between these two techniques?
Controller using a ng-controller directive:
A new $scope is created on ng-controller element.
Explicit view-to-controller connection
Visible with inspect element, etc
Controller in a route:
A new $scope is created per route on the ng-view element.
The controller can request dependencies defined in the route resolve.
Optional view-to-controller connection. Recommended to have a naming convention that maps routes to controllers to views.
One of well-known feature of Angularjs is Single-Page Applications.
If you assign ng-controller attribute directly on the page:
<body ng-controller="PhoneListCtrl">
...
</body>
you can't switch controllers easily for other tasks.
So, use route to switch controllers is one of important step in learning Angular Single-Page feature.
You can have same layout and one different element by using route and ng-view directive.
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/tablets', {
templateUrl: 'partials/tablet-list.html',
controller: 'TabletListCtrl'
}).
If '/phones'
<div ng-view></div>
will include your 'partials/phone-list.html' template
and set 'PhoneListCtrl' as div controller
The same:
If '/tablets'
<div ng-view></div>
will include your 'partials/tablet-list.html' template
and set 'TabletListCtrl' as div controller
This is the difference between two.
ng-view is the cause of the difference. You can't really do this
<div ng-view ng-controller="PhoneListCtrl">
As you'd need to change that controller as the route changed. So basically the router does that for you, and uses the controller you specified when you defined your routes.
You probably can do this:
<div ng-view>
and then in your template:
<div ng-controller="PhoneListCtrl">
and leave out the controller declaration in your routes. Which I suspect would have essentially the same effect, although I've never tried that. Probably better to go with convention here though.
In the 1st case the controller is directly on the page.
Once they change it, that controller is only on the page if the route is /phones otherwise it is some other controller based on some other route.
Yes - the change is this:
if you want to display a specific controller on the page, you can use
<body ng-controller>
BUT
if you want to do routing (application with more than one controller) - you will need to use routing + change the body to:
<body ng-view></body>
I have noticed in a few tutorials and code examples floating around the internet developers using a global AppController in their applications and modules.
Is it best practice to create a global AppController in AngularJS?
I do see some benefits such as being able to handle events in a "global" scope such as:
app.controller('AppController', function($scope, $rootScope, $route, $location){
$rootScope.$on('$routeChangeStart', function(event, current, previous) {
console.log('Do something...');
});
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
console.log('Do something...);
});
});
are there any other advantages or disadvantages to this pattern?
Purely in context of situation. Let's take an example of dynamically changing title tags and page view:
.config(['$routeProvider','$locationProvider',function($routeProvider,$locationProvider){
$routeProvider.when('/', {
template: '/views/home.html',
title:'Home'
});
$locationProvider.html5Mode(true);
}]);
.controller('app', ['$scope','$route','$location',function($scope,$route,$location){
$scope.$on("$routeChangeSuccess",function($currentRoute,$previousRoute ){
$scope.title = $route.current.title;
$scope.page = $route.current.template;
});
}]);
Now both our title and page view are being dynamically loaded in through app level controller that wraps our application. This can be very useful.
<html lang="en" ng-controller="app">
<head>
<title>{{title}}</title>
</head>
<body>
<ng-include src="page"></ng-include>
</body>
</html>
Here's an example of when not to use it. Let's say one of our partial pages return data from an API:
<!-- search.html -->
<div ng-repeat="item in items">
{{item.title}}
</div>
And in our app level controller we are pulling data via broadcast:
$scope.$on('searchComplete',function(d){
$scope.items = d
});
That partial will show the data as we intended however - problems could arise when other child partials use items where scope is being overwritten.
<!-- other-search.html -->
<div ng-controller="OtherSearch" ng-click="search()">
<div ng-repeat="item in items">
{{item.title}}
</div>
</div>
In this partial, ng-click is guiding the users request. So if the app level controller already binded items in the parent, the user will see a list of items when toggling to this partial even if they never triggered the action of search().