I have a simple Angular app (for training purpose since I am a Angular-rookie :)) with a ul-list containing some books. If the user clicks on a book a detail view will appear below the list with some details about that book. I want that if the user clicks on the book the url should change to something like /#/[book-id]. The user should also of course be able to browse directly to this url where the details view for the specific book is visible. I have not figure out how to do this with routes. I paste my sample code below:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body ng-app="libraryApp">
<div id="list" ng-controller="listCtrl">
<ul ng-repeat="book in data.list">
<li>{{ book.name }}</li>
</ul>
</div>
<div id="detailView" ng-controller="detailCtrl">
<div ng-if="data.currentBook" style="background-color: #EEE; padding: 10px 0;">
<h1>{{ data.currentBook.name }}</h1>
<div>Number of pages: {{ data.currentBook.pages }}</div>
</div>
</div>
</body>
</html>
<script>
angular.module("libraryApp", [])
.factory("dataFactory", function() {
return {
list: [
{ id: 1, name: "The Great Gatsy", pages: 423 },
{ id: 2, name: "1984", pages: 332 },
{ id: 3, name: "The Lord Of The Rings", pages: 632 }
],
currentBook: null
};
})
.controller("listCtrl", function($scope, dataFactory) {
$scope.data = dataFactory;
$scope.openDetailView = function(book) {
$scope.data.currentBook = book;
};
})
.controller("detailCtrl", function($scope, dataFactory) {
$scope.data = dataFactory;
});
</script>
you have to put this code in your code ...
angular.module("libraryApp", ['ngRought'])
.config(function ($routeProvider)
{
$routeProvider
.when("/bookname",
{
templateUrl: "path of the html file",
controller: "listCtrl"
})
.when("/date",
{
templateUrl: "path of the html file",
controller: "detailCtrl"
})
Kinda difficult to answer since there are so many ways to do this, but look into https://github.com/angular-ui/ui-router
You'll use your module's config block to set up the routing with $stateProvider, then specify the controllers and templates you'd like to use when a user changes the application's state. This means you'll probably need to move those divs for your different views to separate files (or something creative to get their content -- getting the element's html with jQuery or something would work).
I'm not going into many details because this is something that can be answered easily now that you know to use ui-router :)
It's called nested view. To use it you'd be better try ui-router: https://angular-ui.github.io/ui-router/sample/#/contacts/1/item/b
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.
I've been searching around this afternoon trying to figure out how to use Typescript to change the html of a span element in my breadcrumb trail, OR get an angular statement to evaluate/compile in a jQuery selector. The closest I've found is to use $compile, but I'm not sure if this will work since I don't have the data until after my resolve completes? If it will, I'll need a hand understanding where to inject $compile into the app.
index.module.ts
angular.module('pccrm', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ngMessages', 'ngAria', 'ngResource',
'ui.router', 'ui.bootstrap', 'feature-flags', 'trNgGrid', 'pascalprecht.translate', 'toastr', 'cgBusy',
'fixtable', 'angularUtils.directives.uiBreadcrumbs', 'LocalStorageModule'])
...
index.route.ts
...
.state(Constants.SEARCH_CONTACTS_CONTACTPROFILE, {
url: '/orgs/:externalOrgId/contacts/:profileId',
data: {
displayName: 'Contact Profile'
},
views: {
'': {
templateUrl: 'app/contacts/contact-profile.tmpl.html',
controller: 'ContactsProfileController',
controllerAs: 'cpc',
resolve: {
contactProfile: function (contactProfileService: IContactProfileService, $stateParams: any) {
return contactProfileService.getContactProfile(<string>$stateParams.externalOrgId, <string>$stateParams.profileId)
.then(function (contactModel: IContact) {
return contactModel;
});
}
}
}
}
})
...
contact-profile.tmpl.html
...
<div class="info-group">
<div class="profileImage default">
</div>
<h4 class="contact-name">{{ cpc.contactProfile.fullName() }}</h4>
{{ cpc.contactProfile.title }}<br/>
<a ui-sref="search.organizations.orgProfile({externalOrgId: cpc.contactProfile.externalOrganizationId })" ng-if="cpc.contactProfile.externalOrganizationId">
{{ cpc.contactProfile.externalOrganizationName }}
</a>
</div>
...
Is something like...
<script type="text/javascript">
$('.breadcrumb li.active span').html(
$compile("{{ cpc.contactProfile.fullName() }}")(scope));
</script>
on the end of the template html the best way to do this? Or can my profile service edit the DOM somehow once it retrieves the contact info?
NOTE We're using angular-util-sui-breadcrumbs to generate the BCT...which currently doesnt support interpolating the resolve into the BCT with the way we have our nested named views. This is why I need to be able to modify the BCT dom after the fact.
Or can my profile service edit the DOM somehow once it retrieves the contact info
Yes. Export the stuff on the scope and use that {{somethingOnScope.contactProfile.fullName()}} in the UI.
More on scope : https://docs.angularjs.org/guide/scope
Update
You may have misread my question
No. I am saying that don't do:
$('.breadcrumb li.active span').html(
$compile("{{ cpc.contactProfile.fullName() }}")(scope));
Instead your html should look like:
<ul class="breadcrumb">
<li class="active">
<span>{{somethingOnScope.contactProfile.fullName()}}</span>
</li>
</ul>
And then you don't need jquery 🌹
I am having a few issues getting my head around why this is not working:
template
<div>
<ul>
<li ng-repeat="x in get">
{{ x.name }}
</li>
</ul>
</div>
controller
angular.module('app')
.controller('SubstancesCtrl', function ($scope) {
$scope.get = [{name: "LOL"}];
});
routes
angular.module('app')
.config(function ($routeProvider) {
$routeProvider
.when('/', { controller: 'PostsCtrl', templateUrl: '/templates/posts.html' })
.when('/register', { controller: 'RegisterCtrl', templateUrl: '/templates/register.html' })
.when('/login', { controller: 'LoginCtrl', templateUrl: '/templates/login.html' })
.when('/substances', { controller: 'SubstancesCtrl', templateUrl: '/templates/substances.html'})
});
index.html
<!DOCTYPE html>
<html ng-app='app'>
<head>
<link rel='stylesheet' href='http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css'>
<link rel='stylesheet' href='/app.css'>
</head>
<body ng-controller='ApplicationCtrl'>
<nav class='navbar navbar-default'>
<div class='container'>
<ul class='nav navbar-nav'>
<li><a href='/#/'>Posts</a></li>
<li><a href='/#/register'>Register</a></li>
<li><a href='/#/login'>Login</a></li>
<li>Substances</li>
</ul>
<p ng-if='currentUser' class='navbar-text navbar-right'>
Signed in as {{currentUser.username}}
</p>
</div>
</nav>
<div class='container' ng-view></div>
<script src='http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.4/angular.js'></script>
<script src='http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.4/angular-route.js'></script>
<script src='/app.js'></script>
</body>
</html>
I can see that the template is being replaced by the ng-view directive however the get variable is not being treated in the manner i thought it would: i thought i would get one list item node with the value of LOL
You angular module has not been created, You should declare your module in app.js. As you are using angular routing you need to include its module in your app module.
angular.module('app',['ngRoute'])
Also you need to update your Angular to stable versions 1.4.4 is stable one, because you are using 1.3.0-rc.4 in which rc stands for release candidate which is pre-release version, which may have bug in most of the cases. Thats why I told you to go for stable version of AngularJS. You could also use close stable version which is 1.3.14
Additionally your template has <li ng-repeat="x in get()"> but get function is not defined in the scope, resultant would be nothing would be render on the UI.
angular.module('app')
.controller('SubstancesCtrl', function ($scope) {
$scope.lol = "LOL";
$scope.get = function(){
//write a code here which will return list
//so that ng-repeat will loop through the list
//& will show that data on HTML
//something like below
return {"name": "LOL"}; //in real case there must be something different object to return.
}
});
Alexis King was quite correct in that there were 3 very embarrassing issues with the code, it should have looked like this ( -_- )
template
<div>
<ul>
<li ng-repeat="x in get">
{{ x.name }}
</li>
</ul>
</div>
controller
angular.module('app')
.controller('SubstancesCtrl', function ($scope) {
$scope.get = [{name: "LOL"}];
});
routes were exactly the same.
The biggest issue however was in my gulp script which failed to pick up changes in these new files, I have rewrote the build script to ensure all files from the directories containing these files now are watched and all changes are reflected in the browser.
My excuse: need more coffee.
I'm using requireJS and AngularJS to write my webapp. It works nicely besides the browser back and forward history. This is how my url looks:
.when('/spaces', { ...
<a href="#spaces"> This takes me to the page but the back and forward buttons do nothing. if I change this to <a href="#/spaces"> then the back and forward button works but the template won't appear.
I'm using this boilerplate: https://github.com/fdore/AngularJS-Boilerplate
Can you take a look at this and try to fix it?
The back buttons work for me when I try that. Check this HTML:
<body ng-app="app">
<div>
<ul>
<li>Home</li>
<li>About</li>
</ul>
<div ng-view=""></div>
</div>
</body>
And this JavaScript:
angular.module('app',['ngResource']);
angular.module('app').config(function($routeProvider){
$routeProvider.when('/index',{
template: "HELLO {{name}}",
controller: "IndexCtrl"
}).when('/about',{
template: "HELLO {{name}}",
controller: "AboutCtrl"
}).otherwise({
template:'HELLO {{name}}',
controller: "IndexCtrl"
})
});
angular.module('app').controller('IndexCtrl',function($scope){
console.log("Loading Index");
$scope.name = "Index";
});
angular.module('app').controller('AboutCtrl',function($scope){
console.log("Loading About");
$scope.name = "About";
});
When I run this, the navigation works with clicking the links and the forward/backwards buttons.
Suppose you are using routes:
// bootstrap
myApp.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.when('/home', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
});
$routeProvider.when('/about', {
templateUrl: 'partials/about.html',
controller: 'AboutCtrl'
});
...
And in your html, you want to navigate to the about page when a button is clicked. One way would be
<a href="#/about">
... but it seems ng-click would be useful here too.
Is that assumption correct? That ng-click be used instead of anchor?
If so, how would that work? IE:
<div ng-click="/about">
Routes monitor the $location service and respond to changes in URL (typically through the hash). To "activate" a route, you simply change the URL. The easiest way to do that is with anchor tags.
Go Home
Go to About
Nothing more complicated is needed. If, however, you must do this from code, the proper way is by using the $location service:
$scope.go = function ( path ) {
$location.path( path );
};
Which, for example, a button could trigger:
<button ng-click="go('/home')"></button>
Here's a great tip that nobody mentioned. In the controller that the function is within, you need to include the location provider:
app.controller('SlideController', ['$scope', '$location',function($scope, $location){
$scope.goNext = function (hash) {
$location.path(hash);
}
;]);
<!--the code to call it from within the partial:---> <div ng-click='goNext("/page2")'>next page</div>
Using a custom attribute (implemented with a directive) is perhaps the cleanest way. Here's my version, based on #Josh and #sean's suggestions.
angular.module('mymodule', [])
// Click to navigate
// similar to <a href="#/partial"> but hash is not required,
// e.g. <div click-link="/partial">
.directive('clickLink', ['$location', function($location) {
return {
link: function(scope, element, attrs) {
element.on('click', function() {
scope.$apply(function() {
$location.path(attrs.clickLink);
});
});
}
}
}]);
It has some useful features, but I'm new to Angular so there's probably room for improvement.
Remember that if you use ng-click for routing you will not be able to right-click the element and choose 'open in new tab' or ctrl clicking the link. I try to use ng-href when in comes to navigation. ng-click is better to use on buttons for operations or visual effects like collapse.
But
About
I would not recommend. If you change the route you might need to change in a lot of placed in the application. Have a method returning the link. ex:
About. This method you place in a utility
I used ng-click directive to call a function, while requesting route templateUrl, to decide which <div> has to be show or hide inside route templateUrl page or for different scenarios.
AngularJS 1.6.9
Lets see an example, when in routing page, I need either the add <div> or the edit <div>, which I control using the parent controller models $scope.addProduct and $scope.editProduct boolean.
RoutingTesting.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testing</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-route.min.js"></script>
<script>
var app = angular.module("MyApp", ["ngRoute"]);
app.config(function($routeProvider){
$routeProvider
.when("/TestingPage", {
templateUrl: "TestingPage.html"
});
});
app.controller("HomeController", function($scope, $location){
$scope.init = function(){
$scope.addProduct = false;
$scope.editProduct = false;
}
$scope.productOperation = function(operationType, productId){
$scope.addProduct = false;
$scope.editProduct = false;
if(operationType === "add"){
$scope.addProduct = true;
console.log("Add productOperation requested...");
}else if(operationType === "edit"){
$scope.editProduct = true;
console.log("Edit productOperation requested : " + productId);
}
//*************** VERY IMPORTANT NOTE ***************
//comment this $location.path("..."); line, when using <a> anchor tags,
//only useful when <a> below given are commented, and using <input> controls
$location.path("TestingPage");
};
});
</script>
</head>
<body ng-app="MyApp" ng-controller="HomeController">
<div ng-init="init()">
<!-- Either use <a>anchor tag or input type=button -->
<!--Add Product-->
<!--<br><br>-->
<!--Edit Product-->
<input type="button" ng-click="productOperation('add', -1)" value="Add Product"/>
<br><br>
<input type="button" ng-click="productOperation('edit', 10)" value="Edit Product"/>
<pre>addProduct : {{addProduct}}</pre>
<pre>editProduct : {{editProduct}}</pre>
<ng-view></ng-view>
</div>
</body>
</html>
TestingPage.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.productOperation{
position:fixed;
top: 50%;
left: 50%;
width:30em;
height:18em;
margin-left: -15em; /*set to a negative number 1/2 of your width*/
margin-top: -9em; /*set to a negative number 1/2 of your height*/
border: 1px solid #ccc;
background: yellow;
}
</style>
</head>
<body>
<div class="productOperation" >
<div ng-show="addProduct">
<h2 >Add Product enabled</h2>
</div>
<div ng-show="editProduct">
<h2>Edit Product enabled</h2>
</div>
</div>
</body>
</html>
both pages -
RoutingTesting.html(parent), TestingPage.html(routing page) are in the same directory,
Hope this will help someone.
Another solution but without using ng-click which still works even for other tags than <a>:
<tr [routerLink]="['/about']">
This way you can also pass parameters to your route: https://stackoverflow.com/a/40045556/838494
(This is my first day with angular. Gentle feedback is welcome)
You can use:
<a ng-href="#/about">About</a>
If you want some dynamic variable inside href you can do like this way:
<a ng-href="{{link + 123}}">Link to 123</a>
Where link is Angular scope variable.
just do it as follows
in your html write:
<button ng-click="going()">goto</button>
And in your controller, add $state as follows:
.controller('homeCTRL', function($scope, **$state**) {
$scope.going = function(){
$state.go('your route');
}
})