I have an app that behaves normally when I follow links on the page, but if I use the browser's back and forward buttons, it breaks in the following ways:
It sends a request to the server, but only on "Back".
The template is not rendered at all.
In addition, when I hit "back" to go from page B to page A, chrome's "refresh/stop" button flickers between the top options rapidly, and repeated attemptes to go back and forward causes longer flickering.
Here are the code snippets that I think are relevant:
Edit: I'm working on a plnkr but the site is currently not working. I'll update when it's up and I can verify the bad behavior
Edit 2: Here is the plnkr, but it has problems. It can't find the templateUrls specified in app.js routing, not sure why. Here's the code anyway http://plnkr.co/edit/6cQtnvLi10sJKW8jVzVM
Edit 3: With the help of a friend, I think the problem is coming from using turbo-links on rails 4. I can't test it right now, but when I can I'll post an answer if it works.
file: app.js
window.App = angular.module('app', [
'templates',
'ui.bootstrap'
])
.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when('/', {
controller: 'HomeCtrl',
templateUrl: 'home.html'
})
.when('/bars', {
controller: 'BarsPublicCtrl',
templateUrl: 'bars_public.html'
})
.when('/bars/:bar_name', {
controller: 'BarsDetailPublicCtrl',
templateUrl: 'bars_detail_public.html'
})
.otherwise({redirectTo: '/'});
}]);
file: bars_public_ctrl.js
App.controller('BarsPublicCtrl', ['$scope', '$location', 'BarsPublicDataFactory',
function($scope, $location, BarsPublicDataFactory) {
// memoization
$scope.bars = $scope.bars || BarsPublicDataFactory.getBars();
}
]);
BarsPublicDataFactory just returns a static array of fake data, same with the factory in the following snippet
file: bars_detail_public_ctrl.js
App.controller('BarsDetailPublicCtrl', ['$scope', '$routeParams', 'BarsDetailPublicDataFactory',
function($scope, $routeParams, BarsDetailPublicDataFactory) {
$scope.bar = {};
$scope.bar.name = $routeParams.barId;
$scope.barDetails = BarsDetailPublicDataFactory.getBaz($routeParams.bar_name);
$scope.Bazs = BarsDetailPublicDataFactory.getBazs();
}]);
file: bars_public.html
<div class="container">
<div ng-repeat="bar in bars">
<div class="row">
<div class="col-sm-12">
<a href="/bars/{{bar.name}}">
<h4 style="display:inline;">{{ bar.name }}</h4>
</a>
</div>
</div>
<hr />
</div>
</div>
file: bars_detail_public.html
<select ng-model="searchSelect.style" style="width:100%;">
<option value='' selected>All</option>
<option ng-repeat="baz in bazs">{{baz}}</option>
</select>
<div>
<accordion close-others="true">
<accordion-group ng-repeat="foo in foos | filter:searchSelect">
<accordion-heading>
<div>
<h3>{{foo.name}}</h3>
<em>{{foo.style}}</em>
</div>
</accordion-heading>
</accordion-group>
</accordion>
</div>
If you need anything else, let me know.
It turns out that the problem was caused by turbolinks with Rails 4. I failed to mention it because I didn't realize it was important.
I don't know exactly what caused it, but turbolinks injects some javascript, and as best as I can tell, it highjacks some events that cause the page to reload when you use the browse buttons which was breaking my app.
So I followed this advice: http://blog.steveklabnik.com/posts/2013-06-25-removing-turbolinks-from-rails-4
and it worked just fine! Hope someone else can benefit.
befoure:
[installed]jquery_turbo_links
[installed]turbolinks
alter:
[installed]jquery_turbo_links
[removed]turbolinks
It worked!
Related
first of all sorry if I write with bad grammar/expressions, my english is not the best.
Well, I'm trying to show a product via ID, for this I'm sending this ID from a list of products with this url: localhost/products/product/:ID and I'm receiving GET http://localhost/products/product/101 404 (Not Found)(the 101 is an example).
If I go to http://localhost/products/product.html it is changed for http://localhost but is not redirected, just change the url in the address bar
Here is my code
var app = angular.module('AppMarketApp', ['ngRoute']);
app.config(function($routeProvider, $locationProvider){
$locationProvider.html5Mode({
enabled:true,
requireBase: false});
$routeProvider
.when("/products/product/:codProd", {
templateUrl: '../js/product/appInfo.html',
controller: 'Controller'
})
.otherwise({redirectTo:'/'});;
});
app.controller("Controller",['$scope','$http', '$routeParams', function($scope,$http, $routeParams){
$scope.row = {};
var codProd= $routeParams.codProd;
//some extra code here.
directive
app.directive('appInfo', function() {
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: '../js/product/appInfo.html'
};
});
and html
<body ng-app="AppMarketApp" ng-controller="Controller">
<div class="page" style="">
<div class="content-showproduct">
<div class="product" ng-view>
<app-info info="arts"></app-info>
</div>
</div>
</div>
<script src="../js/product/Controller.js"></script>
<script src="../js/product/appInfo.js"></script>
</body>
Any ideas? if you guys need some extra info let me know.
In addition, I think that I have some bad code in the HTML file, more specifically here
<div class="product" ng-view>
<app-info info="arts"></app-info>
</div>
I dont know if it will work well after routing. Without ng-view in others files works well. But is not important right now.
When I test my index.html on Firefox with console.log it reads a strange error that says. I can't make the oage run on Google Chrome or IE.
junk after document element
This error is caused by the main.html page
<h1>This is my main</h1>
<h3>Scope value: {{ name }} </h3>
I'm just learning angular.js, in fact my code is exactly like this tutorial I was following, but I can't figure out why is not working. Can anyone point me in the right direction and tell me:
Why am I getting the console log error: Junk after document error, and
why can't I make ngview and templateURL work on my site?
Thanks!
My Plnkr Example
App.JS:
var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'pages/main.html',
controller: 'mainController'
})
.when('/second', {
templateURL: 'pages/second.html',
controller: 'secondController'
})
});
myApp.controller('mainController', ['$scope', '$log', function($scope, $log) {
$scope.name = 'Main';
}]);
myApp.controller('secondController', ['$scope', '$log', function($scope, $log) {
$scope.name = 'Second';
}]);
Index.HTML
<header> <nav class="navbar navbar-default"> <div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">AngularJS</a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><i class="fa fa-home"></i>Home</li>
<li><i></i>Second</li>
</ul> </div> </nav> </header>
<div class="container">
<div ng-view></div>
</div>
Main.HTML
<h1>This is my main</h1>
<h3>Scope value: {{ name }} </h3>
Second.HTML
<h1>This is my second</h1>
<h3>Scope value (on second page): {{ name }} </h3>
the code does not run on IE or Chrome cause they don't have a built in localhost feature. Firefox does.
Regarding the Error, I am not 100% sure but I believe that it has to do with Angular HTML format support in the browser itself. I am taking the same course now and facing the same issue. But the app is working fine except for those errors in Firefox.
Chrome: no errors.
MS Edge: no errors.
IE: no errors
===========================
update
Try using Brackets text editor, and use the Live Preview feature.
Open the Index.HTML page in Brackets and hit the button on the top right corner.
I have found a number of posts talking about models/views not updating, but I still can't figure this out. I'm new to Angular, btw so I suspect this is noob issue.
I have the below Angular app.
When the text input test_var is edited, the edited value isn't updated in the sidebar, but it is in the view. Why and how do I fix it?
This works when I don't use views and routes.
I've tried a sidebar controller, but no difference. I've tried $rootScope, which partially worked (it broke other functionality), but I'd prefer not to use a global scope.
Thanks for taking a look.
HTML
<body>
<div ng-app="rxApp" ng-controller="WizardCtrl">
<div class="ng-view">
</div>
<div class="sidebar">
<span ng-bind="test_var"></span>
</div>
</div>
</body>
View (One.html)
<input ng-model="test_var" />
<span ng-bind="test_var"></span>
Controller
rxApp.controller( 'WizardCtrl', function ( $scope, $http, $routeParams, $location, FileUploader ) {
$scope.test_var = 'please work!';
)};
Routes
rxApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/one', {
templateUrl: 'templates/one.html',
controller: 'WizardCtrl'
}).
when('/two', {
templateUrl: 'templates/two.html',
controller: 'WizardCtrl'
}).
otherwise({
redirectTo: '/one'
});
}
]);
Controllers are disposed when transmuting routes.
As for Best Practice you should create a Service to handle that data. You should not use controllers to carry data between views. In your case, the problem is Controllers are disposed when transmuting routes.
See the angular docs on how to use controllers correctly. http://docs.angularjs.org/guide/dev_guide.mvc.understanding_controller
The problem is the making of model variables.
You have to have a dot in model. Make your model point to an object.
So in your controller do like this -
rxApp.controller('WizardCtrl',function($scope, $http, $routeParams,$location, FileUploader){
$scope.test ={
var : 'please work!'
};
)};
View (One.html)
<input ng-model="test.var" />
<span ng-bind="test.var"></span>
HTML
<body>
<div ng-app="rxApp" ng-controller="WizardCtrl">
<div class="ng-view">
</div>
<div class="sidebar">
<span ng-bind="test.var"></span>
</div>
</div>
</body>
To read more about scope go through this UnderStanding Scopes
I am having a very troubling problem where ng-click updates the expected scope variables, the scope variables appear to change on the DOM ( when viewed via the chrome debugger) but the dom elements that have changed are not redrawn in the browser. I have noticed across multiple browsers and devices BUT ONLY WHEN THE SCREEN WIDTH IS BELOW 768. I am using angular version 1.2.6. Has anyone come across this type of issue??
I have simplified the code to try to isolate and confirm what is happening. Here is the code in its simplified version:
First the view:
<section class="stream-area">
<div class="group">
<div class="gw-fixed-top-panel">
<div class="group-heading ">
<div class="panel-title">
<span class="fleft name" ng-click="usergroup.collapsed=!usergroup.collapsed"> CLICK HERE </span>
<a ng-show="usergroup.collapsed" title="Click to edit group" ><i class="fa fa-cog"></i></a>
<a ng-hide="usergroup.collapsed" title="Click to edit group" ><i class="fa fa-chevron-up"></i></a>
<div> {{usergroup.collapsed}}</div>
</div>
</div>
</div>
</div>
</section>
The controller does nothing at this point...
'use strict';
(function () {
var groupController = function($scope) {
$scope.usergroup={};
$scope.usergroup.collapsed=true;
};
myOverall.myApp.controller('GroupController',['$scope', groupController]);
}());
The controller is invoked by via .config:
(function () {
golfWire.gwWebApp =angular.module('gwWebApp', [
'ngRoute',
'ngAnimate',
'ngResource',
'ui.bootstrap',
'firebase',
'LocalStorageModule',
'ngGrid'
]);
myOverall.myApp
.config(['$routeProvider','$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/group/view', {
controller: 'GroupController',
templateUrl: '/app/views/group.html'
})
.otherwise({
redirectTo: '/main'
});
/* $locationProvider.html5Mode(true); */
}]);
Add this function in your controller
$scope.toggleUserGroup = function(){
$scope.usergroup.collapsed = ! $scope.usergroup.collapsed;
$scope.$apply();
}
Call this function on ng-click. This should get the DOM updated and refreshed.
Reasoning: By calling $apply() you trigger a digest() cycle, which checks for changed expression and repaints the DOM if need be.
Incase this doesn't fix the issue, please provide a plunkr/fiddle. Would be happy to get some working code.
Thanks,
A slight variation on Eliel's answer in AngularJS - bind to directive resize worked for me. In the directive.js:
$scope.onResizeFunction = function() {
};
// Call to the function when the page is first loaded
$scope.onResizeFunction();
angular.element($(window)).bind('resize', function() {
$scope.onResizeFunction();
$scope.$apply();
});
I call
$(window).resize();
from within my app.js. The directive's d3 chart now resizes to fill the container.
I would like to change the background image of the application(Html Body) based on the url. And this I want to do in angularJS only :)
For eg:
1) if user visits the url like this,
www.domain.com/view1
Bellow image is shown
2) If user visits url
www.domain.com/view2
I want show other image
app.js
var app = angular.module('app', []);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: 'MyCtrl1'});
$routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: 'MyCtrl2'});
$routeProvider.otherwise({redirectTo: '/view1'});
}])
app.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
}]);;
Controler.js
app.controller('MyCtrl1',function($scope){
$scope.viewBackground="body"
console.log($scope.viewBackground);
})
app.controller('MyCtrl2',function($scope){
$scope.viewBackground="profile"
})
in the partial html, I am just doing like this
<div class="span12">
<p>
{{$scope.viewBackground}}zxz
</p>
</div>
But some reason I am not able to get the value of viewBackground property value.
I'm not sure I understand you correctly, but I hope so.
You have 2 options.
First - use different controllers for each page view1 and view2.
And use ng-class directive on the pages:
HTML:
<!-- "page" View 1 -->
<div ng-controller="View1Ctrl">
<div ng-class="viewBackground"> View 1 </div>
</div>
<!-- "page" View 2 -->
<div ng-controller="View2Ctrl">
<div ng-class="viewBackground"> View 2 </div>
</div>
JS:
var app = angular.module('app', []);
function View1Ctrl($scope) {
$scope.viewBackground = "background-small"
}
function View2Ctrl($scope) {
$scope.viewBackground = "background-big"
}
On your CSS:
.background-small{
height:200px;
width:200px;
background: url('...img1...');
}
.background-big{
height:400px;
width:400px;
background: url('...img2...');
}
Second option - use .run block, where you will add some logic to change the bg-image, but this is a poor option
If your controller you can check the $routeParams param and then set a scope variable to control the background image.
function announcements_detail_controller($scope, $rootScope, $routeParams, $http, $location)
{ //console.log($routeParams);
$scope.css_class_for_background_image = 'xxxx';//
}