AngularJs Change url generated using index of and routeparams - angularjs

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}}">

Related

.dot template and angular or what should I use here?

This is a generic question don't need the "ready to use" code , but an idea where should invest my time in. I set mustache tag because may be similar.
This is an express (4) application using .doT template where i want to expand with some angular (1.4.3) features.
Doesn't seem possible to me to work with .doT template and angularjs , I'm i right here? .I'm trying get it to work a .html template file and his angular application without success( return a 404 cause don't find a template, but when i use with ejs, it does work ( because it read .html files)
2 . STILL , would like to know in case i'm wrong above. considering this anwer that state is possible to use multiple view engine with consolidate. is possible and how would it be done with angular? (just a hint, doens't need to be the whole implementation)
I know by this answer would be possible to use this below, but also says is better to use a helper, is possible to use helpers in.doT template ? , how?
appModule.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
});
considering the above. Which one of 2 and 3 whould you say would be faster?
it would considerably be faster if I change my app to ejs view engine ?
Point by point :
This is incorrect , .doT template works well with Angular, I have use it both, as long as you render a route with dot.
router.get("/blog/new", function(req, res) {
res.render("owner/blog/create");
});
and set a state in your angular provider like
$stateProvider
...
.state("owner-new-blog", {
url: "/blog/new",
templateUrl: "/owner/blog/new",
controller: "CreateUpdateCtrl"
})
There is no point to use consolidate middleware, .doT template works with angular template out of the box, unless you change .doT default parameters.
Yes ... that would be like this , like state in this post
var dT = require('doT');
var tpl = {
tmpl:dT.template('{{=this.helper()}}'),
helper: function(){
/* do what you want to do */
}
}
tpl.tmpl(); // render template
as you can see in this benchmark , .doT is pretty fast if you set double engine in you app , is a bit slowe since you are expanded is functionallity, if you set a helper in doT is less painfull than having two engines .. so , is faster adding a Helper to dot.
there is no point in changing to ejs , dot is pretty fast and an advance template engines which suport layouts and partials. and still , in my opinion, is faster.

Dynamic parameters with ui-router

I'm developing a search app with angular using ui-router.
Requirements:
The search form has too many fields and all have to be optional.
Users should share with another users the URL that display the page with the result list. (So I need to use querystring)
So I could have urls like
path/to/url/list?p=123&v=876
path/to/url/list?c=yes&a=true&p=123
path/to/url/list?z=yes&c=yes&a=true&p=123
path/to/url/list?z=yes&v=876&a=true&p=123
And endless combinations. I know that I can use $location.search() to get all params in json format. That is great! but the question is How can I define the url state with ui-router? Define explicitly all params in the url is not an option. I have read many post but I didn't find a concrete answers.
If you're getting parameters from $location you don't need to define them in state explicitly.
I think, the best way is to use 'resolve' property of $stateProvider configuration:
$stateProvider.state('mystate', {
// Some code here
resolve: {
queryData: ['$location', ($location) => {
$location.absUrl(); // Contains your full URI
return true;
}]
}
});
It's kind of initialization. After that, ui-router will cut URI, but you will store needed data. This case also works fine, when user passing URI directly in browser address input.
Also you can try to set $urlRouterProvider with $urlMatcher for this purposes, but it will be more difficult.

Angular choose html file based on url parameter

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

AngularJS register controller once

That's what I'm doing. There is application with pages and different controls that may be put on pages by site admin/editor. All pages share one ng-app defined on master page. All controls are supplied with .js files with angular controllers. Let's suppose that I have an image gallery block:
<div ng-controller='imageGalleryCtrl'>
do something amazing here
</div>
<script src='imageGallery.js'></script>
Inside script there is a simple controller registration like:
angular.module('myApp').controller('imageGalleryCtrl', ... );
So. If I have 10 image galleries, I'll execute controller registration 10 times. It looks like this will work, but hell - I don't want it to be so =)
For now I just have all controls' scripts registration on a master page, but I don't like it as well, because if there is no image gallery on a page, I don't want it's script be downloaded during page load.
The question is - is there any proper way to understand if controller have been registered in a module already and thus prevent it from re-registering?
---------------
Well, though I've found no perfect solution, I must admit that the whole idea isn't very good and I won't think about it before my site will grow too big to assemble whole angular app on master page.
You should declare your controller but once. Instead of having one controller per gallery, have your single controller handle all image galleries. The controller should make a request to the REST backend to fetch the images of the desired gallery.
I see that instead of ng-view, you're using the ng-controller directive, indicating that probably you're not using Angular's routing. Try switching to using routes.
Have a look at Angular.js routing tutorial. It shows you how to use the ngRoute module. Then, in the next chapter, the use of $routeParams is described. Via the $routeParams service, you can easily say which gallery should be displayed by providing its ID in the URL; only one controller will be necessary for all your galleries.
If you really must check whether a given controller has been declared, you can iterate through the already declared controllers (and services... and pretty much everything else) by checking the array angular.module("myApp")._invokeQueue. The code would probably look something like this (not tested!):
var isRegistered = function(controllerName)
{
var i, j, queue = angular.module("myApp")._invokeQueue;
for (i = 0, j = queue.length; i < j; ++i) {
if (
queue[i][0] === "$controllerProvider"
&& queue[i][1] === "register"
&& queue[i][2][0] === controllerName
) {
return true;
}
}
return false;
};
Bear in mind however that while this may (or may not) work, it's far from being the correct thing to do. It's touching Angular's internal data that's not meant to be used in your code.

How can I dynamically set templates without messy query parameters in angular ui-router?

I'm building an artist portfolio web app where the artist can create a 'project' which consists of a series of content pieces (mostly images at this point) which can then be put in an order and the artist can choose between different preset layouts. I'm using angular and node + express. I'm struggling to find a good way to dynamically set templates. The only functional scheme i've devised so far is to put the template name in a query parameter in the url like this.
ui-sref="webapp/project/photo?template=vertical"
then in ui-router it's relatively simple to set the template using state params
templateUrl : function (stateparams) {
return 'templates/' + stateparams.template + '.html';
},
Although it's functional I don't like this mostly because it creates messy urls and allows anyone to change templates with query params or more likely load something without a real template because the url was typed incorrectly or correctly without the query parameter.
I can't make an api call from the templateUrl function because it's not injectable so I can't use the $http service. I've tried to use template provider but haven't made anything functional out of that yet. It does allow for an injectable function but that function must return an entire template instead of a url. If I can get a template url for it how can a load the template with that? I assume I'm not the first person to want dynamic templates (templates set in the database) from angular. What are my best options?
I have found a functional solution to my problem using ui-router, $stateParams, and $http. I'll be looking for a better architecture scheme as this necessitates 3 server requests every time a project is requested. One to get the template name and another to load the template file and another to load the project data. I suppose I only added one request to the norm. Anyways.. This solution is working for me but next I will be moving the logic to get template by the project name to an angular service to keep everything clean.
.state('projects/:project_url', {
url : '/projects/:project_url',
templateProvider : function ($stateParams, $http) {
return $http.get('/api/projects/' + $stateParams.project_url)
.then(function (data) {
// get template name
var templateName = data.data[0].template;
// return template by name
return $http.get('/pages/' + templateName + '.html')
.then(function (data) {
return data.data;
});
});
},
controller : 'projectCtrl'
});
http://dotjem.github.io/angular-routing/ supports your scenario with inject-able template functions. Note however that you must provide the raw template in the return statement, but that is easily done using the $template service...
It is very similar to UIRouter, so it should be a fairly easy transition if you find it worth it.
http://plnkr.co/edit/dkPIWMW236ixifETohNW?p=preview
If you take the latest stable release rather than the head you must add a "get" call to that service as: $template.get('template.html') rather than the newer: $template('template.html')

Resources