deep linking, page reloads, angular js - angularjs

I have a table which should be filtered depending on the url.
This is my module::
angular.module('myApp', ['pipelibservice']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/pipes/:pipeID', {templateUrl: 'partials/wizard.html', controller: PipeListCtrl});
}]);
In my template I have a list with a href that should filter the table:
<li ng-repeat="pipe in pipes">
<a href='#/pipes/{{ pipe.code }}'>{{ pipe.code }} - {{pipe.title_en}}</a>
</li>
This is my index.html
<!doctype html>
<html ng-app="myApp">
<head>
<meta charset="utf-8">
<title>Google Phone Gallery</title>
<link rel="stylesheet" type="text/css" href="css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="css/app.css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-strap/0.7.2/angular-strap.min.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
<script src="lib/angular/angular-resource.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
Problem is, the entire page reloads when I hit the link. I only want the url to change so my table is filtered. How do I fix so the page is not reloaded?
Update:
I've narrowed it down to the rest API call. If i replace the rest call with hardcoded values (from the orginal rest-call) then it works. Any idea what can be wrong?

you cant normally use $route and not refresh the page. but in your case i would just use a filter http://docs.angularjs.org/api/ng.filter:filter
<li ng-repeat="pipe in pipes | filter: pipeID">
<a href='#/pipes/{{ pipe.code }}'>{{ pipe.code }} - {{pipe.title_en}}</a>
</li>
dont forget to put in ctrl $scope.pipeID = $routeParams.pipeID
P.S. i wrote a post explaning a bit simpler Ben Nadels idea (which is awesome) and its a way to use $route without refreshing http://bresleveloper.blogspot.co.il/2013/08/breslevelopers-angularjs-tutorial-basic_20.html
the point is that using $route with templateUrl and/or controller creates new instances of the controller and view, and by ur description u dont want it. so u can drop the templateUrl controller and send a custom parameter and in the app use ngSwitch to switch ngInclude and u manage it all with 1 controller

As per ngHref documentation, you should use ng-click to prevent the page reload:
{{ pipe.code }} - {{pipe.title_en}}
You would need to create the goToPipe function in your controller, with something like:
$scope.goToPipe = function (pipe_code) {
$location.path("/pipe/" + pipe_code);
};

The only solution I've found to this problem so far is this:
http://www.bennadel.com/blog/2441-Nested-Views-Routing-And-Deep-Linking-With-AngularJS.htm
Take a look at their demo:
http://bennadel.github.io/AngularJS-Routing/#/pets/cats/10/medical-history
Notice the tabs BACKGROUND, DIET, MEDICAL HISTORY and how the do not refresh the page.
However this solution is very complex and involves and employing a lot of non-native to angular stuff.
I'm still looking to find a simpler solution to this simple problem.

Related

AngularJS ngRoute not working as expected

I'm trying to use the ngRoute in my angularJS page, but I'm not able to load my content within ng-view.
HTML:
<!DOCTYPE html>
<html>
<head>
<title></title>
<link href="CSS/index.css" rel="stylesheet" />
<script src="Scripts/angular.min.js"></script>
<script src="Scripts/angular-route.js"></script>
<script src="Scripts/app/index.js"></script>
</head>
<body ng-app="app">
<header>
<a ng-href="#/add-new">Add new</a>
</header>
<div ng-view></div>
<footer>
#Copyright 2017
</footer>
</body>
</html>
index.js:
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/add-new', {
template: 'Some content'
})
}]);
Not sure what I'm missing here.
If I add otherwise condition on $routeProvider, it gets loaded. Please let me know what am I missing here so that the content within my $routeProvider.when gets loaded in my ng-view on markup. Thanks
Also not getting any console errors.
try this
JS:
app.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "index.htm"
})
.when("/add-new", {
templateUrl : "add.htm"
})
});
HTML:
Red
Add this below line in your HTML page
<base href="/">
and change ng-href to href
EDIT :
$location in HTML5 mode requires a <base> tag to be present!
If you using ng-href, the you should pass $scope object
You don't have entry point for the app, so if you load your app and you are not going to specific url you will not see any results.
You can add otherwise({redirectTo:'/add-new'}) or go to #/add-new to see your page

remove hashes when dealing with routes in AngularJS

I have made a sample SPA using angular. I used Angular routing feature, to have a single layout page, and then inject and swap out different views depending on the URL the end user has requested.
Everything works perfectly fine with the hashes in the href routes on the index page
page1
but by doing so, my URL of the webpage will be like http://localhost/angular/#/page1
So I wanted to remove the hashes in the URL and make it like http://localhost/angular/page1
To remove the hashes, you will have to enable the html5Mode routing and also set the base href on the index page
https://docs.angularjs.org/error/$location/nobase
I did exactly the same (please see my code snippet below), however it does not work. I'm running this on local host Apache server.
var app = angular.module("myModule", ["ngRoute"])
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when("/page1", {
templateUrl: "partials/page1.html",
controller: "page1Controller"
})
.when("/page2", {
templateUrl: "partials/page2.html",
controller: "page2Controller"
})
$locationProvider.html5Mode(true);
})
.controller("page1Controller", function($scope) {
$scope.message = "Page1";
})
.controller("page2Controller", function($scope) {
$scope.message = "Page2";
})
<html ng-app="myModule">
<head>
<title>Angular Routing</title>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript" src="angular-route.js"></script>
<script type="text/javascript" src="js.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
<base href="angular"></base>
</head>
<body>
<table>
<h3>Sammple Routing in AngularJS</h3>
<tr>
<td class="leftMenu">
page1
page2
</td>
<td class="mainContent">
<ng-view></ng-view>
<!--partials will be filled here-->
</td>
</tr>
</table>
</body>
I'm struggling with this on IIS right now and in my struggles, stumbled across an excellent guide for Apache: https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/
I hope it helps.
I followed this article to remove the hashes from URLs: https://scotch.io/tutorials/pretty-urls-in-angularjs-removing-the-hashtag Here is the quick code for what he does:
app.js or every angular page:
app.config(["$locationProvider",
function($locationProvider) {
$locationProvider.html5Mode(true);
}
]);
Angular template or each angular page must include this in the head:
<base href="/">
I'm not at all sure of the inner workings so I can't explain what exactly this does. Everything I know about this is from that article so feel free to take a look.
Edit: Could be a problem with try using an empty string like It prevents hashes from being added to the url when clicking dead links but still gives the anchor hover effect.

Loading partial views in angular controller into empty document

Given an empty document with just the bare essentials, loading js files and stylesheet:
<!doctype html>
<html ng-app="labApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script src="/static/lab.js"></script>
<link rel="stylesheet" href="/static/local.css" />
<link rel="stylesheet" href="/static/superhero.min.css" />
</head>
<body ng-controller="labController">
</body>
</html>
And an empty controller in lab.js:
angular.module('labApp', [])
.controller('labController', function() {
var lab = this;
});
How do I go about loading a partial view into the body?
Am I supposed to do things like that manually, using jQuery, or is there some hidden facility in angular to load partials?
You can do this by rendering different views with ui-router: https://github.com/angular-ui/ui-router
When loaded into your application, you can include it like this in
angular.module('app', [ui.router])
When you follow the documentation it is pretty easy to setup different routes. Good luck!

How to hide and show templates rather than destroy and reinject them everytime

I am using ui-router and Named views. it works flawlessly but it doesn't suit my purpose. I don't want the templates to be injected everytime i click on the menu item but only the first time it is clicked after application is loaded. The remaining times, it should simply hide the template and show the template that is currently active for a menu click. when coming back to the original menu click, it should just do ngShow="true" for the hidden template and hide the current one. Is that possible to do without editing the cleanupLastView() in the angular-ui-router?
If i comment out the cleanupLastView(), it simply keeps on injecting templates and does nothing to older templates. So both end up showing. Tried to debug the cleanupLastView() but i couldn't figure out what variables are available to me there so i could re-show what ever is clicked a second time rather than inject again.
index.html
<!DOCTYPE html>
<html lang="en">
<head ng-app="myApp">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="style.css" rel="stylesheet">
<script type="text/javascript" src=".lib/angular-1.3.0/angular.js"></script>
<script type="text/javascript" src="./angular-ui-router.js"></script>
<script type="text/javascript" src="./modular/ct-ui-router-extras.core.js"></script>
<script type="text/javascript" src="./modular/ct-ui-router-extras.dsr.js"></script>
<script type="text/javascript" src="../timerService.js"></script>
<script type="text/javascript" src="../dataService.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<div class="navbar navbar-default navbar-static-top" role="navigation">
<ul class="nav navbar-nav">
<li ng-class="{active: $state.includes('main')}"><a ui-sref="home">Main</a></li>
<li ng-class="{active: $state.includes('files')}"><a ui-sref="files">Files</a></li>
</ul>
</div>
<div>
<div ui-view="pane"></div>
</div>
</div>
</body>
</html>
app.js
var myApp = angular.module("myApp", [ 'ui.router', 'ct.ui.router.extras.dsr']);
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state('main',
url:"/main",
deepStateRedirect: true,
views : {
pane: {
templateUrl : 'tpl.pane-0.html'
},
}
)
.state('files',
url: '/files',
deepStateRedirect: true,
views : {
pane : {
templateUrl : 'tpl.pane-1.html'
},
'first#files' : {
templateUrl : 'tpl1.first.html',
deepStateRedirect: true
},
'second#files' : {
templateUrl : 'tpl1.second.html',
deepStateRedirect: true
},
},
)
});
tpl.pane-0.html
<div>
<input type='text'></input>
</div>
tpl.pane-1.html
<div >
<div data-ui-href='first'></div>
<div data-ui-href='second'></div>
</div>
tpl1.first.html
<div>
<input type='text'></input>
</div>
tpl1.second.html
<div>
Second
</div>
This is the simplified code of my app. it works to do the multiple named views but fails at deepStateRedirect which seems to be the one associated with nav bar type of templates rather than(?) Sticky. Is that correct? I added the param deepStateRedirect: true to allthe views being injected but to no avail. if the tpl1.first.html's input text box is written and the view switched to main, and come back, there is no text to be found in the input box. What am i doing wrong?
Yes, you can do this but it requires some custom work.
Change the state so that it uses an empty template.
In the state's controller check if the document already contains the HTML for the view (use a unique ID).
If required, use the $template cache and $compile to create the original template view and append it to the document body.
In the template, you can use ng-show="isState_expression | isState" expression to toggle the visibility of the template.
Basically the ui-routes work the same as before, but you're handling the compiling of the template yourself. Once it's in the DOM (not inside the ui-view). You can just leave it there to be handled by ng-show.
I don't recommend using resolve on the state since it's going to become a static state.
Here's the manual on $compile:
https://docs.angularjs.org/api/ng/service/$compile
Here's a tutorial on $compile:
http://www.benlesh.com/2013/08/angular-compile-how-it-works-how-to-use.html
Here's a stack answer on $compile:
Compiling dynamic HTML strings from database
Why doesn't it suit your needs? Do you need to preserve the states when they are not shown?
If so, perhaps you should look into UI Router Extras Sticky States. It allows you to preserve the $scope of a state and not create/destroy it every time. This would be better than trying to reinvent the wheel.
Take a look at the sample.

Why does adding AngularJS break Bootstrap template?

Why does adding AngularJS to a page break it? What can I do to allow it to function correctly? Controls stop rendering. Menus stop expanding.
I am trying to divide the index.html page of an existing Bootstrap theme into partials / templates. Unfortunately, as soon as I move the HTML out of the index.html the controls on that page break.
The theme I am using is KingAdmin v1.3 from WrapBootstrap.com: https://wrapboo...
The only markup I'm adding is...
ng-app="app"
<div ng-include="'shell.html'"></div>
<script src="assets/thirdparty/angular/1.2.26/angular.js"></script>
<script src="assets/app/app.js"></script>
The shell.html contains only the portion of the body that was in the index originally...
WITHOUT ANGULAR:
WITH ANGULAR:
INDEX.HTML:
<head>
<title>Dashboard | KingAdmin - Admin Dashboard</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="KingAdmin - Bootstrap Admin Dashboard Theme">
<meta name="author" content="The Develovers">
<!-- CSS -->
<link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" media="screen">
<link href="assets/css/font-awesome.min.css" rel="stylesheet" type="text/css" media="screen">
<link href="assets/css/main.css" rel="stylesheet" type="text/css" media="screen">
<!--[if lte IE 9]>
<link href="assets/css/main-ie.css" rel="stylesheet" type="text/css" media="screen" />
<link href="assets/css/main-ie-part2.css" rel="stylesheet" type="text/css" media="screen" />
<![endif]-->
<!-- Fav and touch icons -->
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/ico/kingadmin-favicon144x144.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="assets/ico/kingadmin-favicon114x114.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="assets/ico/kingadmin-favicon72x72.png">
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="assets/ico/kingadmin-favicon57x57.png">
<link rel="shortcut icon" href="assets/ico/favicon.png">
</head>
<body class="dashboard">
<div ng-include="'shell.html'"></div>
<!-- Javascript -->
<script src="assets/js/jquery/jquery-2.1.0.min.js"></script>
<script src="assets/js/bootstrap/bootstrap.js"></script>
<script src="assets/js/plugins/modernizr/modernizr.js"></script>
<script src="assets/js/plugins/bootstrap-tour/bootstrap-tour.custom.js"></script>
<script src="assets/js/king-common.js"></script>
<script src="assets/js/plugins/stat/jquery.easypiechart.min.js"></script>
<script src="assets/js/plugins/raphael/raphael-2.1.0.min.js"></script>
<script src="assets/js/plugins/stat/flot/jquery.flot.min.js"></script>
<script src="assets/js/plugins/stat/flot/jquery.flot.resize.min.js"></script>
<script src="assets/js/plugins/stat/flot/jquery.flot.time.min.js"></script>
<script src="assets/js/plugins/stat/flot/jquery.flot.pie.min.js"></script>
<script src="assets/js/plugins/stat/flot/jquery.flot.tooltip.min.js"></script>
<script src="assets/js/plugins/jquery-sparkline/jquery.sparkline.min.js"></script>
<script src="assets/js/plugins/datatable/jquery.dataTables.min.js"></script>
<script src="assets/js/plugins/datatable/dataTables.bootstrap.js"></script>
<script src="assets/js/plugins/jquery-mapael/jquery.mapael.js"></script>
<script src="assets/js/plugins/raphael/maps/usa_states.js"></script>
<script src="assets/js/king-chart-stat.js"></script>
<script src="assets/js/king-table.js"></script>
<script src="assets/js/king-components.js"></script>
<script src="assets/thirdparty/angular/1.2.26/angular.js"></script>
<script src="assets/app/app.js"></script>
</body>
</html>
UPDATE 2014-11-25
I've confirmed this is not me. I had a friend attempt to convert a single page in the template to Angular partials using ng-include tags and setting it up behind a proper Node.JS server. He had the same results. As soon as Angular renders the first page, tons of functionality breaks. the expand/collapse logic everywhere stops working. Most of the controls stop rendering properly.
NOTE
Someone mentioned that the problem might be caused by the use of ng-include tags and partials WITHOUT the partial file having a contoller. The side bar, top bar, breadcrumb are all being included as static HTML / Jade files via an ng-include. A route is passing in the controller for the main body, however the problems exist within this area as well.
Here is a link to the template on the developer's site:
KingAdmin Dashboard Theme
And here is how it currently looks:
Quick look at the modifications from the index.html page:
PARTIALLY RESOLVED:
Not sure if this would be considered a hack. Someone with more knowledge of jQuery and Angular could / should chime in to tell you if this is safe.
STILL UNRESOLVED:
This seems to work while the page is being loaded for the first time. It does NOT work if you navigate away from the page and back again (using the back button, for example). I believe this is happening due to Angular injecting the body and NOT re-rendering the entire page... or the scripts. There's probably something that can be done within each template that uses jQuery (re-init somehow, etc.).
There seem to be tons of questions / examples discussing similar problems with the DOM, jQuery, and using timeouts to correct them:
AngularJS: How can I run a directive after the dom has finished rendering?
The entire fix is in with your common resource scripts, king-common.js, etc.. They each have several rendering functions that appear to be called up front, however the DOM is still being rendered.
Example:
$(document).ready(function(){
$('.main-menu .js-sub-menu-toggle').click( function(e){
[snip]
$li.find('.sub-menu').slideToggle(300);
});
By wrapping each of these operations in a setTimout you postpone rendering until after the DOM is modified:
$(document).ready(function(){
setTimeout(function(){
$('.main-menu .js-sub-menu-toggle').click( function(e){
[snip]
$li.find('.sub-menu').slideToggle(300);
},1000);
);
These have been moved to the tail end of your scripts.jade / scripts.html file. This was done initially as an attempt to delay the firing of these methods, so this might be unnecessary. Still, that's part of how we arrived at a functioning template.
Your problem is Bootstrap is not watching for the newly created elements on your page that angular compiles for you. You can create directives that can call the the Bootstrap jQuery method that add the Bootstrap bindings to your element, such as ($('.dropdown').dropdown()).
There is a wonderful AngularJS library that replaces that is an angular agnostic rewrite of bootstrap.js that may fix this for you: http://angular-ui.github.io/bootstrap/
For a quick hack, if you want all your elements with the .dropdown class to use Bootstrap dropdown, you would create a directive like this.
angular.module('app')
// Directives: https://docs.angularjs.org/guide/directive
.directive('dropdown', [
// Use window dependency
'$window',
// Returns a directive
function ($window) {
return {
// Restrict to attribute, or class name so can be used like so:
//
// <a class="dropdown btn btn-primary">Dropdown button</a>
// or
// <a dropdown class="btn btn-primary">Dropdown button</a>
restrict: 'AC',
link: {
post: [
// This dependency gives you the element with
// the directive wrapped as a jQuery object
'$element',
function ($element) {
$element.dropdown();
}
]
}
};
})
I think you should reconsider your dependencies. The elements broken in your UI seems to require jquery, for instance: jquery.easypiechart.min.js
At https://docs.angularjs.org/misc/faq you can read:
Does Angular use the jQuery library? Yes, Angular can use jQuery if
it's present in your app when the application is being bootstrapped.
If jQuery is not present in your script path, Angular falls back to
its own implementation of the subset of jQuery that we call jQLite.
Angular 1.3 only supports jQuery 2.1 or above. jQuery 1.7 and newer
might work correctly with Angular but we don't guarantee that.
Notice that angular requires jQuery 2.1 or above, whilst Bootstrap require the latest 1.1.x version of jQuery (Bootstrap does not support jQuery 2+ due to jQuery 2 does not support IE8).
After reading the above you should also read:
Does one need jQuery when using Twitter Bootstrap with Angular.js?
https://github.com/angular-ui/bootstrap/issues/2765

Resources