Due to security reasons, JavaScript/AngularJS does not allow the loading of local files when running the app locally, off of your desktop. You must either have a localhost instance or run the whole thing from a web server.
In my case, I'd like to place the entire angular app in an eBook implementation. So, I do need to be able to run it as if it is on the desktop.
An alternative way to load the templates is to use the script id tag. In that case, template content is hardcoded in the index.html or the app.js.
But not exactly sure how to go about it?
How do we convert the following config code to script ID based implementation? And while I'm at it, let me also throw in this question as well; Are there any disadvantages of choosing this approach - other than the obvious modularity ( code organization )?
Here is the code that needs to be converted to id based approach.
I'm not sure how to convert the "resolve", "controllerAs" information thru the script-id based implementation.
angular.module("quickquiz").config(["$routeProvider", "$mdThemingProvider", function ($routeProvider, $mdThemingProvider) {
$mdThemingProvider.theme('default')
$routeProvider
.when("/home", {
templateUrl: 'templates/home.html',
controller: 'HomeController',
controllerAs: 'home',
resolve: {
quizConfig: ["QuizConfig", function (QuizConfig) {
return QuizConfig.loadConfig();
}],
quizStorage: ["QuizStorage", function (QuizStorage) {
return QuizStorage.loadQuizes();
}]
}
})
.when("/:currentPage", {
templateUrl: 'templates/main.html',
controller: 'MainQuizController',
controllerAs: 'main',
resolve: {
quizConfig: ["QuizConfig", function (QuizConfig) {
return QuizConfig.loadConfig();
}],
quizStorage: ["QuizStorage", function (QuizStorage) {
return QuizStorage.loadQuizes();
}]
}
})
.when("/:1", {
templateUrl: 'templates/main.html',
controller: 'MainQuizController',
controllerAs: 'main',
resolve: {
quizConfig: ["QuizConfig", function (QuizConfig) {
return QuizConfig.loadConfig();
}],
quizStorage: ["QuizStorage", function (QuizStorage) {
return QuizStorage.loadQuizes();
}]
}
})
.otherwise("/home");
}]
);
I know that the solution to my problem pass thru an implementation as follows; but again, not exactly sure how to deal with those "resolve" portion here;
[script type="text/ng-template" id="/tpl.html"] Content of the
template. [/script]
source: https://docs.angularjs.org/api/ng/directive/script
You can load templates directly into the cache in a script tag, or by consuming the $templateCache service directly. $templateCache.
I'm developing a web application based on angular.js ui-router. I have a page where a lot of info is loading (news, products etc.). This info initializes through state resolves.
$stateProvider
.state("cabinet", {
url: "/cabinet",
template: "app/views/cabinet/index.html",
resolve: {
news: ["NewsService", function (newsSvc) {
return newsSvc.getList();
}],
user: ["UserProfileService", function (userSvc) {
return userSvc.me();
}],
services: ["ServiceService", function (serviceSvc) {
return serviceSvc.getList();
}],
products: ["ProductService", function (productSvc) {
return productSvc.getList();
}],
templates: ["TemplateService", function (templateSvc) {
return templateSvc.getList();
}]
})
.state("cabinet.profile", {
url: "/cabinet/profile",
template: "app/views/profile/index.html"
})
...
Can I reload only of on resolves of state "cabinet" when I move from another page? For example, I come back from "cabinet.profile" to "cabinet" and I want to reload not all resolves, but only "user". Is it possible? Google tells me nothing about this.
$state.go("cabinet", {}, {reload: true}) - reload all resolves.
I am learning Angular. I am watching a 2 years old video, and I am trying to use route concept and using in view1.CShtml (Remember, its CShtml and not html, while in the video, he uses html).
I also find it wierd that Views path starts as ~Views/View1.cshtml (Fair enough I have it in Views folder) on contrary to Partial/View1 where the video demonstrator has. Now, I do not understand what is this "~" for when I have similar directory structure like demonstrator.
Also, sadly, the view1 is not loading :( What is the problem? Of course he use single module and controller, but I am trying to use dependent module also for my own learning....What's the problem here?
angular.module('App', ['myFirstApp']).controller('Fir', function ($scope) {
$scope.Customers = [
{ name: 'Kiam', city: 'Los Angeles' },
{ name: 'Se', city: 'Los Vegas' }
]
}).config(function ($routeProvider) {
$routeProvider
.when('/View1',
{
controller: 'Fir',
templateUrl: '~Views/View1.cshtml'
})
.when('/View2',
{
controller: 'First',
templateUrl: '~Views/View2.cshtml'
})
.otherwise({ redirectTo: '/View1' });
});
var temp = angular.module('myFirstApp', []);
var controllerCollection = {};
controllerCollection.First = function ($scope) {
$scope.Customers = [
{ name: 'Sita', city: 'Los Angeles' },
{ name: 'Ram', city: 'Los Vegas' },
]
};
temp.controller(controllerCollection);
.cshtml pages are C# razor pages, which need to be loaded using ASP.net view engine, Like you could declare one action inside A controller and do return a cshtml view from there
Code
public ActionResult View1()
{
return View();
}
Or else you need to create a static folder, which will not been included in Views folder, Asp.net restricted access to the views folder.
See reference SO Answer
you could try like this .when('/View1', { controller: 'Fir', templateUrl: '/MyViews/View1'}), it's enough. and also check the route config the routing path is added or not. If you are using the $routeprovider it will automatically generated the routing path in global.asax.
No need to specify additionally the .cshtml for the view page to be displayed.
I'm making a single page application (SPA). I made a controller called InitialControler to load the data from the server at this url (local.app/init).
I want this url to be opened before any other url. I'm using ui-router, I did a $state.go('init') in the .run() function but it still load the requested page before the 'init' page
First create state called app
$stateProvider.state('app', {
abstract: true,
templateUrl: "assets/partials/container.html",
controller: 'AppCtrl',
resolve: {
init: function(MyFactory) {
return MyFactory.resolver();
}
}
});
Now, any new state you create should be child state of app state. This is also good because it become sort of your root scope. And state will not process unless your factory resolves.
This is how you create your factory
app.factory('MyFactory', function($http){
var items = [];
return {
resolver: function(){
return $http.get('my/api').success(function(data){
items = data;
})
},
get() {
return items;
}
}
});
Now in any other state
$stateProvider.state('app.items', {
url: '/items',
templateUrl: "assets/partials/items.html",
controller: function($scope, MyFactory){
$scope.items = MyFactory.get();
}
});
More on sate resolve
https://github.com/angular-ui/ui-router/wiki#resolve
If you are using ui-router then you could resolve this using nested states. For example:
$stateProvider
.state("main", {
url: "/",
template: '<div ui-view></div>',
controller: 'InitController'
})
.state("main.landing", {
url: "landing",
templateUrl: "modules/home/views/landing.html",
controller: 'LandingPageController'
})
.state("main.profile", {
url: "profile",
templateUrl: "modules/home/views/profile.html",
controller: 'ProfileController'
});
In this example you have defined 3 routes: "/", "/landing", "/profile"
So, InitController (related to "/" route) gets called always, even if the user enters directly at /landing or /profile
Important: Don't forget to include <div ui-view></div> to enable the child states controller load on this section
One way to do is, in config declare only 'init' state. And in InitialController, after data is loaded(resolve function of service call), configure other states. But in this approach, whenever you refresh the page, the url will change to local.app.init.
To stay in that particular state even after reloading, the solution I found is to have a StartUp app in which I loaded the required data and after that I bootstraped the main app manually by angular.bootstrap.
Currently our project is using default $routeProvider, and I am using this "hack", to change url without reloading page:
services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}]);
and in controller
$locationEx.skipReload().path("/category/" + $scope.model.id).replace();
I am thinking of replacing routeProvider with ui-router for nesting routes, but cant find this in ui-router.
Is it possible - do the same with angular-ui-router?
Why do I need this?
Let me explain with an example :
Route for creating new category is /category/new
after clicking on SAVE I show success-alert and I want to change route /category/new to /caterogy/23 (23 - is id of new item stored in db)
Simply you can use $state.transitionTo instead of $state.go . $state.go calls $state.transitionTo internally but automatically sets options to { location: true, inherit: true, relative: $state.$current, notify: true } . You can call $state.transitionTo and set notify: false . For example:
$state.go('.detail', {id: newId})
can be replaced by
$state.transitionTo('.detail', {id: newId}, {
location: true,
inherit: true,
relative: $state.$current,
notify: false
})
Edit: As suggested by fracz it can simply be:
$state.go('.detail', {id: newId}, {notify: false})
Ok, solved :)
Angular UI Router has this new method, $urlRouterProvider.deferIntercept()
https://github.com/angular-ui/ui-router/issues/64
basically it comes down to this:
angular.module('myApp', [ui.router])
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider.deferIntercept();
}])
// then define the interception
.run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
$rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
// Prevent $urlRouter's default handler from firing
e.preventDefault();
/**
* provide conditions on when to
* sync change in $location.path() with state reload.
* I use $location and $state as examples, but
* You can do any logic
* before syncing OR stop syncing all together.
*/
if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
// your stuff
$urlRouter.sync();
} else {
// don't sync
}
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
}]);
I think this method is currently only included in the master version of angular ui router, the one with optional parameters (which are nice too, btw). It needs to be cloned and built from source with
grunt build
The docs are accessible from the source as well, through
grunt ngdocs
(they get built into the /site directory) // more info in README.MD
There seems to be another way to do this, by dynamic parameters (which I haven't used).
Many credits to nateabele.
As a sidenote, here are optional parameters in Angular UI Router's $stateProvider, which I used in combination with the above:
angular.module('myApp').config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('main.doorsList', {
url: 'doors',
controller: DoorsListCtrl,
resolve: DoorsListCtrl.resolve,
templateUrl: '/modules/doors/doors-list.html'
})
.state('main.doorsSingle', {
url: 'doors/:doorsSingle/:doorsDetail',
params: {
// as of today, it was unclear how to define a required parameter (more below)
doorsSingle: {value: null},
doorsDetail: {value: null}
},
controller: DoorsSingleCtrl,
resolve: DoorsSingleCtrl.resolve,
templateUrl: '/modules/doors/doors-single.html'
});
}]);
what that does is it allows to resolve a state, even if one of the params is missing.
SEO is one purpose, readability another.
In the example above, I wanted doorsSingle to be a required parameter. It is not clear how to define those. It works ok with multiple optional parameters though, so not really a problem. The discussion is here https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090
After spending a lot of time with this issue, Here is what I got working
$state.go('stateName',params,{
// prevent the events onStart and onSuccess from firing
notify:false,
// prevent reload of the current state
reload:false,
// replace the last record when changing the params so you don't hit the back button and get old params
location:'replace',
// inherit the current params on the url
inherit:true
});
Calling
$state.go($state.current, {myParam: newValue}, {notify: false});
will still reload the controller, meaning you will lose state data.
To avoid it, simply declare the parameter as dynamic:
$stateProvider.state({
name: 'myState',
url: '/my_state?myParam',
params: {
myParam: {
dynamic: true, // <----------
}
},
...
});
Then you don't even need the notify, just calling
$state.go($state.current, {myParam: newValue})
suffices. Neato!
From the documentation:
When dynamic is true, changes to the parameter value will
not cause the state to be entered/exited. The resolves will not be
re-fetched, nor will views be reloaded.
This can be useful to build
UI where the component updates itself when the param values change.
This setup solved following issues for me:
The training controller is not called twice when updating the url from .../ to .../123
The training controller is not getting invoked again when navigating to another state
State configuration
state('training', {
abstract: true,
url: '/training',
templateUrl: 'partials/training.html',
controller: 'TrainingController'
}).
state('training.edit', {
url: '/:trainingId'
}).
state('training.new', {
url: '/{trainingId}',
// Optional Parameter
params: {
trainingId: null
}
})
Invoking the states (from any other controller)
$scope.editTraining = function (training) {
$state.go('training.edit', { trainingId: training.id });
};
$scope.newTraining = function () {
$state.go('training.new', { });
};
Training Controller
var newTraining;
if (!!!$state.params.trainingId) {
// new
newTraining = // create new training ...
// Update the URL without reloading the controller
$state.go('training.edit',
{
trainingId : newTraining.id
},
{
location: 'replace', // update url and replace
inherit: false,
notify: false
});
} else {
// edit
// load existing training ...
}
If you need only change url but prevent change state:
Change location with (add .replace if you want to replace in history):
this.$location.path([Your path]).replace();
Prevent redirect to your state:
$transitions.onBefore({}, function($transition$) {
if ($transition$.$to().name === '[state name]') {
return false;
}
});
i did this but long ago in version: v0.2.10 of UI-router like something like this::
$stateProvider
.state(
'home', {
url: '/home',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
controller: 'mainCtrl'
},
}
})
.state('home.login', {
url: '/login',
templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
controller: 'authenticationCtrl'
})
.state('home.logout', {
url: '/logout/:state',
controller: 'authenticationCtrl'
})
.state('home.reservationChart', {
url: '/reservations/?vw',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
controller: 'reservationChartCtrl',
reloadOnSearch: false
},
'viewVoucher#home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
controller: 'viewVoucherCtrl',
reloadOnSearch: false
},
'addEditVoucher#home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
controller: 'voucherCtrl',
reloadOnSearch: false
}
},
reloadOnSearch: false
})
Try something like this
$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})
In Angular 2, the accepted answer from RezKesh translates to the following:
this.uiRouter.stateService.go(
"home.myRouteState",
{
"param1": this.myParam1,
"param2": this.myParam2
},
{ notify: false }
);
Assuming you have injected UIRouter into your component's constructor as follows:
constructor(
private uiRouter: UIRouter
) { }
I don't think you need ui-router at all for this. The documentation available for the $location service says in the first paragraph, "...changes to $location are reflected into the browser address bar." It continues on later to say, "What does it not do? It does not cause a full page reload when the browser URL is changed."
So, with that in mind, why not simply change the $location.path (as the method is both a getter and setter) with something like the following:
var newPath = IdFromService;
$location.path(newPath);
The documentation notes that the path should always begin with a forward slash, but this will add it if it's missing.