I don't know very much about angular, and I'm trying to get the hang of best practices regarding the use of URL routing and states and whatnot. I've got a scenario. It's a simple question, but I'm using it to get a handle on what's available to me.
Say that I have two completely separate web pages for displaying information on Ford cars and Toyota cars. When you access the pages, all you have is the car ID number, so you just hit the url "cars.com/info/id:198273918273". What's the best way, using angular.js, to immediately strip the id number from the url, use it to look up the car make, and display the appropriate html page, all without changing the url displayed at the top of the browser?
you can use functions in your route templateUrl
.when('/your_url/:car_id', {
templateUrl: function(attrs){
//Example of the login yours will be complex i guess :P
if(attrs.car_id == 1) { return 'template_ford.html' }
if(attrs.car_id == 2) { return 'template_toyota.html' }
},
controller : 'someController'
})
and by that your template can be chaged before the page is rendered and no need to send the user to a different url
Assuming that you are using angular-ui router
$stateProvider
.state('car-get', {
url:'/info/{car_id}/',
controller: ['$scope','$stateParams',function($scope,$stateParams){
var car_id = $stateParams.car_id;
// now you can get your car info
// and bind it to your template.
$scope.car = myservice.getcarinfo(car_id) //Here goes your service or your api calls to get car info
}],
templateUrl: 'path_to_detail_car_page.html',
});
Here is a good begginer tutorial for Angular-ui Router
Related
In the address bar of the browser the $routeProvider returns ".../index#/projects/0".
This is the view for that particular project. What I am trying to achieve is to either hide the indexOf value, in this case the "0" and have the url as ".../index#/projects/somethingelse". Linking to the project using <a href="#/projects/{{projects.indexOf(project)}}"> and "/projects/:id" in the $routeProvider config. I have tried certain methods but cannot get any results.
Say for example the the first project in the projects array is called, the url in the browser is "/projects/0". Is it possible to replace the 0 to have the url start at 1 but still return the values of the object in project array[0] and so on. Basically trying to find a rewrite method in the controller or service. Currently grasping AngularJS.
I have come accross this answer but don't know how to go about doing this to achieve what I need. Going by this answer I tried the following code in the controller $location.path($route.updateParams({id:"project"})); it does give the desired result: from ".../index#/projects/0" to "../index#/projects/project" but when navigated to the view, it is blank and the project details are not returned.
Also any good pointers, tutorials, books on URL rewrites and security in AngularJS? The AngularJs version I am using is 1.5.8.
You can use whatever you want in the route params, so long as you can link it to the right data.
If you want to offset the index by 1, simply use something like this (assuming projects is available / injectable)
.when('/projects/:id', {
resolve: {
project: function($routeParams, projects) {
return projects[$routeParams.id - 1];
}
},
// etc
To use an arbitrary property like id, try Array.prototype.find
resolve: {
project: function($routeParams, projects) {
return projects.find(project => project.id === $routeParams.id);
}
}
To create links, you'd use something like
<a ng-href="#/projects/{{projects.indexOf(project) + 1}}">
or
<a ng-href="#/projects/{{project.id}}">
I've seen a couple of similar questions/answers, but I still seem to be missing something. Everything works fine until I refresh the page or go to a URL directly.
I can either get a 404 or create the same url in mvc, but then it serves up the partial only on refresh and doesn't include the layout page.
There were a couple that suggested changing the MVC routing to:
routes.MapRoute(
name: "Application",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" }
);
When that is implemented, it means I can't access any other URL on the site normally and unless I am missing something, basically everything has to be put into a rest api or write a custom route for every url. Neither sounds very good.
So how can I have an html5 url (no hash tags in valid browsers) with angularjs and be able to browse to eg. Home/About or Home then click a link to About and have them show up the same with the same base layout page?
This may not be the best answer, so if anyone has any better ideas, please comment, otherwise maybe this will help someone else.
I realized that the MVC Ajax directive didn't detect angular calls, so I couldn't automate that side.
So in angular I did something like
.when('/Home/Contact', {
templateUrl: '/Home/NgContact'
In my MVC controller I have 2 actionresults:
public ActionResult NgContact(){
ViewBag.IsFromNg = 1;
return Contact();
}
public ActionResult Contact() {
return View("Contact"); //have to type in name, may look for NgContact.cshtml
}
Finally on any views these may call I put:
#if (ViewBag.IsFromNg == 1){ Layout = null; }
So there is a little repetition with each Actionresult having 2 copies, 1 for a full page load and 1 for any calls angular makes, but only 3 extra lines each.
Having created some basic web applications with Angular, still learning and discovering ...
I need to create a Angular application which depends on various parameters used in the application. For example various label string we will retrieve through REST... These labels are used on every screen of the application, including the first screen that is shown on start-up...
I'm looking for a 'proper' / 'good' / 'angular' way to init the application waiting for the result of a sort of 'init-application' rest-call - due to the fact that the result of this rest call contains data the application will need from start on, I have found an example approach below ...
https://blog.mariusschulz.com/2014/10/22/asynchronously-bootstrapping-angularjs-applications-with-server-side-data
Are there any more ideas / thoughts / useful links ...
Thanks!
I would suggest you to explore the 'resolve' property of ngRoute(if you are using ngRoute) or UI-router state:-
While using $routeProvider:-
$routeProvider
.when("/news", {
templateUrl: "newsView.html",
controller: "newsController",
resolve: {
message: function(messageService){
return messageService.getMessage();
}
}
})
Or, if you are using UI Router :-
$stateProvider.state('root',{
abstract:true, // this is abstract statte, controller is in child states.
templateUrl:'/assets/root-module/partial/main/main.html',
resolve : {
securityContext : function($http){
return $http.get("/security/context");
},
token : function(securityService,securityContext){
securityService.setToken(securityContext.data.token);
console.debug(securityContext.data.token);
return securityContext.data.token;
}
}
});
In either of the approaches, just make sure that you DO NOT provide 'ng-controller' in your HTML templates. Rather provide the controller while defining your route|state as the above example suggests.
The properties being "resolved" - if they are promises, the controller (hence the view) won't be initialized until the promise is resolved.
I highly recommend you to explore UI Router state hierarchy approach that allows you to share 'resolved; proerties to the child states.
First, i want to say that English is not my native language, so sorry by advance if i'm not 100% clear.
So let say i want to create a basic CRUD app for cars.
There would be the route "/cars" with the list of all cars.
To get those cars data, i would have to make a call to the API, which will send me all the data about all cars at once, and then display all the cars name. I think i'm right for now ?
The "problem" i have is when the user click on a specific car.
It should redirect the user to the route "cars/CAR_ID" and display this specific car's data. But how to get those data ? I mean, yes i could just make an API call "/api/car/CAR_ID", but why would i do that if i already have everything i need in the first api call with all the cars ?
I've been looking every thread, everywhere and they always make another api call, but it feel like a waste to me, i cant help it.
There got to be a reason why everyone does that and i'm missing it.
I mean, the other way would be to store the first call's data and instead of making the second api call, we could just fetch the data from the first call.
I'm new to web development so it may be better to make a request for every page than store a big set of data the first time and work with it all along the navigation.
If so, can i have some more insight on the subject, it feels like asking to the server something i already know...
A different answer to part of your question.
I mean, yes i could just make an API call "/api/car/CAR_ID", but why would i do that if i already have everything i need in the first api call with all the cars ?
What would happen if you didn't make the first api call? I mean, could't I directly type in my browser /api/car/12345?
Let's consider stackoverflow as an example, let's say I bookmark this question, and later on I open this page (lets assume I have no cached data) directly without going through the page with the questions list. In your scenario I would get a blank page because the creator would assume that I visit some other page first, which is unresonable (not always). Making an api call for each particular entity saves as from such a pitfall from the start because it doesn't assume anything about the browsing history of the user.
Here are the options I can think of.
1) Use ui-router (my preferred option). Here's an example route:
angular.module('carApp')
.config(function ($stateProvider) {
$stateProvider
.state('cars', {
url: '/cars',
templateUrl: 'app/cars/views/index.html',
controller: 'CarsCtrl',
resolve: {
cars : ['Car', function(Car) {
return Car.list();
}]
}
})
.state('cars.show', {
url: '/{carId}',
views: {
"#" : {
templateUrl: 'app/cars/views/show.html',
controller: 'CarCtrl'
}
},
resolve: { // the cars from the parent route (cars) will be injected into this route
car: ['$stateParams', 'cars', function($stateParams, cars) {
// not hitting the web service, find our car using lodash
return _.find(cars, {_id: $stateParams.carId});
}]
}
})
OR
2) Use caching in your services
angular.module('carApp')
.service('Car', function Car($http) {
return {
list: function() {
return $http.get('/cars', {cache: true});
}
};
});
The first time you call Car.list() it will call the web service. Subsequent calls to Car.list() will not call the web service. In your controller you can either call Car.list and find the correct car similar to the cars.show route or add another function to your service that can find a car by ID.
I write an application with angularjs and use ui router for dynamic routing , my app has a page for display list of news and when click on a news , Explanation of the news is showing
for example if I have a news with id=3 when i click on link of this news the url change to news/3 and when click on a news with id=5 url change to news/4 but i want to change url to news/subnews/third or news/subnews/fifth
my piece of code for change url and content is like this
.state('news', {
abstract:true ,
url: "/news",
templateUrl: "views/news/news.html",
})
.state('news.showAll', {
url: "",
templateUrl: "views/news/showAllNews.html",
})
.state( 'news.detail',{
url:"/:newsId",
templateUrl: "views/news/tmpShowDet.html",
controller:"newsShowing",
resolve:{
newsId: ['$stateParams', function($stateParams,newsId){
return $stateParams.newsId;
}]
}
})
what is the true way for display like news/subnews/....
How many 'subnews' do you want?
Translating numbers to words can get a little tricky, and spoken-language specific. Example: at 'subnews/101' do you want 'subnews/onehundredandone or subnews/onehundredandfirst or subnews/oneohone'.
I would recommend, if you only have a few subnews possibilities, going by categories.In that case, it seems you already know how to implement, or have access to the documentation for UrlRouteProvider.
If you have many subnews, I would leave the parameter as an integer, which is relatively spoken-language agnostic. You can always mask it or build a lookup table, etc if you don't want it displayed.
Speaking of which, if you still want to change the integer to a word, just use a lookup, and the url docs.
Cheers, bro