My problem is that when I change the path of my angular app nearly 1 of 10 tries the routing crashes.
Let me explain it a little bit closer. With the crash I mean that the route is changing to the new path but nearly at the same time the URL loses the #
Conroller which is triggered after clicking at a html div with the ng-click:
$scope.showDetailOfEntry = function(id){
$location.path('/detail/' + id);
}
Routing:
.when('/detail/:id', {
title: "Detail-View",
name: "detail",
templateUrl: "./templates/detail.php",
controller: "DetailController"
})
About 9/10 tries the path change is running without any problem.
The URL should be:
http://localhost/MyApp/#/detail/66
But turns into this:
http://localhost/MyApp/detail/66
I think the problem is located at the $location.path();- Maybe it gets sometimes into term problems.
Do you have any idea why this is sometimes happening?
Thank you for your help! I would appreciate every answer.
This seems like an issue referenced to in https://github.com/angular/angular.js/issues/8675 and https://github.com/angular/angular.js/issues/10659
A proposed (temporary) fix for this could be:
angular.module('app', [])
.config(function($locationProvider) {
$locationProvider.hashPrefix('!');
})
That is, until the AngularJS team finds a proper fix.
Related
For quick reading, the problem is simplified under "The problem", and for further information keep going down for background and notes before answering. Thank you!
The problem
I want to delete the instance of a controller when refreshing the page or when moving to a different view and then returning to the same view through the navigator (nav.html). In fact, every time view X.html is visited, I want the program to check if X-controller.js exists, and if it does delete it before making a new instance.
How far am I going here, is it a 2 line solution I failed to find online or am I looking at hours of coding to make this work?
Background
My project uses the $routeProvider service, not the the ng-controller directive. Once the app launches there are constantly two views, one on the top where you can navigate back and forth through the controllers "Home - Contact - Support" (logically, nav.html), and one on the bottom which is the "Home" or "Contact" and so on.
I haven't had any problems with this arrangement until the code begun making massive calculations. The same instance of the controller is updated with more data than it should, calculates for previous data that was discarded, and so on. I've read online about deleting the controller but as far as I know it's not that easy.
Notes before answering the question:
If the second option of 'hours of coding' is the solution I'm not expecting anyone to do this for me, but references to articles or code for that would be appreciated because I haven't found anything useful on my own.
If there is an easier solution that applies only when ng-controller is used and not $routeProvider then it's not an option for me. There are over 20 views and many sections of code which triggers redirection to a different view with a different controller using event listeners. I'm not currently planning on changing $routeProvider to ng-controller.
If the solution doesn't actually delete the previous instance, rather clears the $scope and javascript variables then that could work for me as well.
I haven't included code because this question is not about a bug or error, if for some reason code snippets of the $routeProvider configuration or one view and controller is needed let me know and I'll include that code with the classified sections replaced with similar dummy code.
Clarification Edit
I'll illustrate with an example. Assume X.html is a view controlled by XCtrl.js. $scope.test is initiated in the beginning $scope.test = 2 of that controller, and once a button in the view is clicked $scope.test becomes 3. Also, the X view displays $scope.test all the time. So I moved to that view, clicked the button, and saw that 3 is displayed on the screen. Then I moved to "Home" through the navigator, then back to "X", and 3 is still displayed. But what I want is 2 to be displayed, and not 3. I want everything to be renewed in that controller.
Solution
Eventually I used a different technique to solve this. All the data saved in the local storage was affecting the $scope variables (there were too many variables to track that I didn't notice this). To solve the issue I cleared the local storage key localStorageService.set('keyUsed', []); once the view controlled by controller X is visited. Assume an init function, so the line of code clearing the local storage was placed in the top of that function.
I'm still marking the correct solution from the answers below for the problem I initially thought I had.
Always have a '.' in your ng-models!
-- Miško Hevery (father of AngularJS)
Most likely you have an issue with $scope.test and not with controller itself. If your template x.html refers the value of test as {{test}} (without any prefix) then most probably you are referring the test of the wrong scope. It usually happens due to prototypical chain of scopes that extend one another and fallback to prototype property value. In this case, choose something unique for XCtrl controller and put all your state inside this controller to that namespace. For example, use x as namespace
$scope.x = {};
$scope.x.test = 2;
instead of just
$scope.test = 2;
Then in x.html refer the value as
{{x.test}}
This is one of the Angular best practices.
Another best practice, that may solve your issue, is actually not using $scope at all, but use controller instance itself for storing state in junction with controllerAs syntax:
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.min.js#1.5.8" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular.min.js"></script>
<script data-require="angular-route.min.js#1.5.8" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular-route.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-view>
</body>
</html>
script.js
angular.module('app', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/x', {
controller: 'xCtrl',
controllerAs: 'x',
templateUrl: 'x.html'
})
.when('/y', {
controller: 'yCtrl',
controllerAs: 'y',
templateUrl: 'y.html'
})
.otherwise({
redirectTo: '/x'
})
}])
.controller('xCtrl', [function() {
var x = this;
x.test = 2;
x.doSomething = function() {
x.test ++;
};
}])
.controller('yCtrl', [function() {
var y = this;
y.hello = 'Hello';
}])
x.html
<h1>X.html</h1>
<p>test = {{x.test}}</p>
<button ng-click="x.doSomething()">+1</button>
Link to Y
y.html
<h1>Y.html</h1>
<p>{{y.hello}}</p>
Link to X
Live Demo:
https://plnkr.co/edit/EpUn94uWMliTaG5mvPxv?p=preview
Links:
To understand the issue with not having a '.' in your model, see this video by Miško Hevery.
To better understand controllerAs approach, you can read this post by Todd Motto.
I am picking up Angular for a project of mine and am having trouble getting my first steps right.
Specifically, I can get a list of items to display via a component and appropriate template, but I can not figure out how to trigger ng-click events using the component model. Many similar problems to this have been answered on SO but I have followed the many corrections and suggestions without progress and need some advice.
file: customerList.js
function CustomerListController($scope, $element, $attrs, $http) {
this.customerList = [
{ name: 'Arya' },
{ name: 'No One' },
];
this.yell = function(customer) {
console.log("customer customer, we've got a click");
};
}
angular.module('myApp').component('customerList', {
templateUrl: 'customerList.html',
controller: CustomerListController,
});
And its template:
file: customerList.html
<div class="customer"
ng-repeat="customer in $ctrl.customerList"
customer="customer"
ng-click="$ctrl.yell(customer);">
Welcome home, {{customer.name}}!
</div>
Even when I set ng-click="console.log('click detected');", I get no console log.
I believe this is sufficient information to diagnose but please let me know if you need more.
Thanks!
First of all, console.log will not work directly in an angular expression. You can't use window functions directly in expressions.
Second, I would recommend using controllerAs syntax as it's a newer school way of doing things. Try accessing the controller with your controllerAs alias in the ng-click() expression.
I'm pretty new to AngularJS and have a little obstacle and wondered if anyone could push me in the right direction.
I am using as part of my routing system for the application a template I have created and then dynamically generate the url with an id taken from specific parts of objects in my controller here is an example:
{
id: 'started',
title: 'Get Started',
image: 'assets/img/enrolment.jpg',
system: 'eLP',
pdf: 'assets/files/getting_started.pdf',
info: 'blah blah blah.'
},
so as you can see, the first part of my object is called 'id' and I have it configured within my $routeProvider as:
$routeProvider.
when('/',
{
templateUrl: 'sessions/guides.html',
controller: 'tutsList'
}).
when('sessions/:id',
{
templateUrl: 'sessions/help.html',
controller: 'tutsList'
}).
otherwise({redirectTo:'/'});
});
(guides.html is working, but help.html is coming back blank currently).
When I hover over the links within list that's generated, I can see the id is now coming through and showing up at the bottom of the page, but the link goes through to a blank template. I am aware that I have to add a controller, which then sticks the id to the $routeParams , but, it doesn't seem to work when I use the phoneApp example process in AngularJS Docs.
Any help would be greatly appreciated.
If your using an android phone, don't you have to specify the directory path from the root directory? (not like appeared to have done for windows ( pdf: 'assets/files/getting_started.pdf'))
Sorry I'm fairly new to this myself.
Google is indexing my Angular.js app's content just fine, i.e. it executes the JS, XHRs, the whole deal, but for some reason the title is not indexed properly and remains the static HTML fallback (default title set by HTML, before JS is executed).
In index.html I have:
<title ng-bind="title + ' — Default Title'">Default Title</title>
and it's set like this whenever the route changes:
app.run ['$location', '$rootScope', ($location, $rootScope) ->
$rootScope.$on '$routeChangeSuccess', (event, current, previous) ->
$rootScope.title = current.$$route.title if current.$$route
]
Example of the page: http://registerzdravil.si/zdravila/aspirin-protect-100-mg-gastrorezistentne-tablete
TL;DR: Google indexes my Angular app just fine, but doesn't index dynamic titles for some reason.
I am fairly sure you do not have much control over this. here are some links:
http://www.hobo-web.co.uk/title-tags/
https://yoast.com/google-page-title/
They both explain that:
Basically, Google says: we know better, you can try and write a title
we like, but we reserve to do whatever to make people click on your
result. There is no way to prevent this from happening right now.
I think I'm missing some basics about Backbone's routing functions.
I'm building an app and it looks something like so:
file: app.js
App = {}
App.nav = new Backbone.Router;
require('app/controller');
file: controller.js
App.nav.route('home', 'home', function () {
console.log("Home Activated");
});
App.navigate('home');
At this point the browser changes the URL in the address bar to /home but nothing happens and I don't get the Home Activated console message.
I've tried using my own routing class (i.e. Backbone.Router.extend({})) but I don't really see a point in it as I still need to initialize it, and I want to use a central history/navigation in my app that all modules/controllers add routing to it rather than creating a router for every controller.
What am I doing wrong?
http://documentcloud.github.com/backbone/#Router-navigate
From the documentation:
If you wish to also call the route function, set the trigger option to true.
But as OlliM wrote, you need to activate the history first!
So your answer should be:
Backbone.history.start();
App.nav.navigate('home', {trigger: true});
edit:
forgot to put "nav"
For the routing to work, you need to call Backbone.history.start() after setting up your routes (basically after you've done everything else). See: http://documentcloud.github.com/backbone/#History-start
I just want to point this out as it saved me a world of hurt and heartache.
If you are routing to a custom page such as
Backbone.router.navigate('/some/page'); // does not work
And it appears to not be working. Add a trailing '/'
Backbone.router.navigate('/some/page/'); // works
This cost me a few hours of troubleshooting...