Angular - Load custom template using dynamic path with fallback - javascript

I want to replace the following code in my routes:
angular.module('app').config ($stateProvider, $urlRouterProvider) ->
.state 'statistics',
controller: 'AppCtrl'
templateUrl: '/app/statistics.html'
By something like this:
angular.module('app').config ($stateProvider, $urlRouterProvider) ->
.state 'statistics',
controller: 'AppCtrl'
templateUrl: Something.resolveTemplatePath('/app/statistics.html')
My goal is to add a prefix based on some configuration, but I need to know if the path with the prefix actually exists.
I need to call this in my routes, so I probably need to put this function is a Provider, right? And I don't really know how to check if the template exists or not. I believe Angular makes an AJAX call to load the template and I saw that I could check if the file is found or not, but I'm not sure what the best solution is.
Because if the file with prefix doesn't exist, then I must load the file without prefix (fallback).
What is the best way to do that? Thanks.

Where would this configuration for the prefix exist? Inside your Angular code or would it be part of a build tool like Gulp/Grunt?
Assuming that this 'prefix' would be an Angular constant by the name TEMPLATE_PREFIX, you could use a combination of $templateCache and the templateProvider given by ui-router to do
templateProvider: Something.resolveTemplatePath('/app/statistics.html')
And the definition of Something as a service as -
angular.module('app').service('Something', function($templateCache, TEMPLATE_PREFIX) {
this.resolveTemplatePath = function(templateURL) {
return $templateCache.get(TEMPLATE_PREFIX + templateURL) || $templateCache.get(templateURL);
}
});
There's a great grunt build task for populating $templateCache - https://www.npmjs.com/package/grunt-angular-templates

Related

Angular ui-view (UI-Router) not rendering template - plunker included

Question Background:
I am using AngulaJS's UI Router for the first time to create two views within my app.
The Issue:
Plunker link: https://plnkr.co/edit/2XAKa6mDCUyzyOPz2CNK
I feel I'm missing something simple here but I cannot get any route to render the specified html templates set in the app.js.
Eventually I want the Update.html template to render when the submit fucntion of the home.html (search()) is clicked but first off I need to be able to actually render a single view which I currently cannot.
I would expect on-load for the route to render up the home.html page but it wont:
Any help sorting this will be much appreciated.
app.js:
angular
.module('app', [
'ui.router'
])
.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html',
controller: 'HomeController'
})
.state('update', {
url: '/update',
templateUrl: 'Update.html',
controller: 'UpdateController'
})
}])
Looking at your plunker briefly, it looks like your controller files are creating new angular apps with the same name. They were overriding each other so the .config() block didn't exist in the final app. I have updated the controller files in this plunker and it seems to be rendering the first ui view fine:
https://plnkr.co/edit/cdpWWOaBJWL3dONtIXzv?p=preview
Notice in the controller files, the angular.module('app') no longer has the second argument ['ui-bootstrap'] which was causing a new angular app to be created for each controller file. Check it out here in the angular docs.
Beware that using angular.module('myModule', []) will create the module myModule and overwrite any existing module named myModule. Use angular.module('myModule') to retrieve an existing module.
Hope this helps!

Angular + RequireJs: Resolve templateUrls of directives

I use angularjs and requirejs in my spa. For the organization of imports and so on I use require. In requirejs I can use e.g. baseUrl: Every import path is resolved with the baseUrl. Now I would like to resolve the templateUrls the same way. Therefore I can use e.g.:
templateUrl = requirejs.toUrl("modules/test/chuck.directive.html")
The problem that I would like to resolve every templateUrl of every directive this way.
So: Is there a possibility to jump into the template loading process of directives in angular and run the above code?
Thanks for any hint.
I would decorate $templateRequest service if you know for sure that you want to intercept all template loading requests and modify template URL. Something like this:
.config(function($provide) {
$provide.decorator('$templateRequest', function($delegate) {
return function(tpl, ignoreRequestError) {
tpl = requirejs.toUrl(tpl); // modify original tpl
return $delegate.call(this, tpl, ignoreRequestError);
};
});
})

Angular UI-router, controller is undefined

I am kind of new to the AngularJS framework and I am trying to migrate my test project using the standard router to use the UI-router, but I get the following error:
Error: [ng:areq] Argument 'mainCtrl' is not a function, got undefined
What I have done so far is:
Controller:
// mainCtrl.js
angular.module("sm-web")
.controller('mainCtrl',['$scope',
function($scope) {
...
}]);
Router:
angular.module('sm-web', ['ui.router'])
.config(['$stateProvider', '$urlRouterProvider', function( $stateProvider, $urlRouterProvider ) {
$urlRouterProvider.otherwise('root');
$stateProvider
.state('root', {
url: '',
templateUrl: path + 'ng/sm/view/main.html',
controller: 'mainCtrl'
});
}]);
Index:
<body ng-controller="mainCtrl">
<main-menu></main-menu>
<div class="container">
<div ui-view></div>
</div>
</body>
This works when I use the standard router, but not with the UI-router. Does anyone have any idea of what I am doing wrong?
It seems you have an issue w/the order you declare things. For you to declare the module "sm-web" you need to do this:
angular.module('sm-web', ['ui.router']);
Note that the presence of that 2nd array argument is what tells Angular that you're declaring the module (eg. creating a new module). When you leave that 2nd argument out, you're retrieving the module you previously declared.
So with that in mind, look at how it all is coming together in your code:
To declare the controller, you retrieve the module "sm-web" (by leaving off the 2nd array arg).
When configuring the router states, you declare a new module "sm-web". But note that immediately after you declare this new module, you try to register a state with the controller named "mainCtrl" -- but that doesn't exist yet.
You need to create the module somewhere before doing all of the above. After creating the module, then register the controller on the module. Finally, with the controller defined, then you can register the state that uses the controller.
There's too many ways to solve this ordering problem, so I'm not going to suggest anything further. It depends on what files the code lives in and the order you load those files in index.html.
In order to avoid your problem change your code by the following code:
// mainCtrl.js
angular.module("sm-web")
.controller('mainCtrl',['$scope',
function($scope) {
...
}]);

Re directing to another page Angularjs

Hi I have am trying to re direct the page to another route with parameter
like this passing id as a parameter.
$location.path('/api/po/'+id);
What is the proper way to re direct to another page using router and parameter? My module, controller etc all are working fine. Just having problem re directing.
Thaks
take a look at this ui router to me is the better way to build a function that move you application from a view to another one. It's really easy to use and very rich of useful method.
Follow these steps
Install ui-router using bower
Include angular-ui-router.js in your index.html
Add 'ui.router' to your main module's list of dependencies
Add a ui-view directive to the some in your html
Set up your states in the module config, following is an example how:
var myapp = angular.module('myapp', ["ui.router"])
myapp.config(function($stateProvider, $urlRouterProvider){
// For any unmatched url, send to /route1
$urlRouterProvider.otherwise("/route1")
$stateProvider
.state('route1', {
url: "/route1",
templateUrl: "route1.html"
})
.state('route2', {
url: "/route2",
templateUrl: "route2.html"
})
})
Refer this in case of doubt.

Angular 1 - get current URL parameters

I want to extract data from current URL and use it in controller.
For example I have this url:
app.dev/backend/surveys/2
Bits that I want to extract:
app.dev/backend/ :type / :id
Is there anything in Angular that could help me with this task ?
To get parameters from URL with ngRoute . It means that you will need to include angular-route.js in your application as a dependency. More information how to do this on official ngRoute documentation.
The solution for the question:
// You need to add 'ngRoute' as a dependency in your app
angular.module('ngApp', ['ngRoute'])
.config(function ($routeProvider, $locationProvider) {
// configure the routing rules here
$routeProvider.when('/backend/:type/:id', {
controller: 'PagesCtrl'
});
// enable HTML5mode to disable hashbang urls
$locationProvider.html5Mode(true);
})
.controller('PagesCtrl', function ($routeParams) {
console.log($routeParams.id, $routeParams.type);
});
If you don't enable the $locationProvider.html5Mode(true);. Urls will use hashbang(/#/).
More information about routing can be found on official angular $route API documentation.
Side note: This question is answering how to achieve this using ng-Route however I would recommend using the ui-Router for routing. It is more flexible, offers more functionality, the documentations is great and it is considered the best routing library for angular.
You could inject $routeParams to your controller and access all the params that where used when the route was resolved.
E.g.:
// route was: app.dev/backend/:type/:id
function MyCtrl($scope, $routeParams, $log) {
// use the params
$log.info($routeParams.type, $routeParams.id);
};
See angular $routeParams documentation for further information.
Better would have been generate url like
app.dev/backend?type=surveys&id=2
and then use
var type=$location.search().type;
var id=$location.search().id;
and inject $location in controller.
In your route configuration you typically define a route like,
.when('somewhere/:param1/:param2')
You can then either get the route in the resolve object by using $route.current.params
or in a controller, $routeParams. In either case the parameters is extracted using the mapping of the route, so param1 can be accessed by $routeParams.param1 in the controller.
Edit: Also note that the mapping has to be exact
/some/folder/:param1
Will only match a single parameter.
/some/folder/:param1/:param2
Will only match two parameters.
This is a bit different then most dynamic server side routes. For example NodeJS (Express) route mapping where you can supply only a single route with X number of parameters.
ex:
url/:id
var sample= app.controller('sample', function ($scope, $routeParams) {
$scope.init = function () {
var qa_id = $routeParams.qa_id;
}
});
Just inject the routeParams service:
http://docs.angularjs.org/api/ngRoute.$routeParams

Categories