I want to render /list after updating the Quiz successfully. How do I do that?
this.update = function() {
Quiz.update($scope.quiz, $routeParams.id)
.success(function() {
// render /list
});
};
Well, the sanest solution would be using routing combined with $location, like this:
this.update = function() {
Quiz.update($scope.quiz, $routeParams.id)
.success(function() {
$location.path('/list');
});
};
Of course, it goes without saying that you need to inject $location into your controller, and define the /list route (I assume you already have this).
Have a look at this is you want additional functionality: https://docs.angularjs.org/api/ngRoute/directive/ngView
Are you using ngroute or ui-router?
If ngroute
$location.path('/list');
If ui-router
$state.go('stateNameForList');
Related
I'm trying to create an AngularJS slideshow app where users can add content within a projects/ directory.
The router already uses variable routes.
.when('/:project', {
templateUrl: function(params) {
return 'projects/' + params.project + '/project.html';
}
})
However, I can't figure out how to use variable Controller names. For example, the following does not work:
.when('/:project', {
templateUrl: function(params) {
return 'projects/' + params.project + '/project.html';
},
controller: function() { return 'SomeController'; }
})
But this does:
.when('/:project', {
templateUrl: function(params) {
return 'projects/' + params.project + '/project.html';
},
controller: 'SomeController'
})
Is it possible to associate a controller with a route using a function?
If this sounds like a silly idea, let me explain what I'm trying to do. Instead of having user's edit the MainController, I'd like to be able to write JavaScript specific to a project. If a project gets deleted, that project's specific JavaScript is also deleted. If a new project gets added that needs custom JavaScript, users can use an API (AngularJS Events) to interact with the UI.
What's the best way to do something like this?
UI Router has controllerProvider feature. ngRoute doesn't have it.
The function specified in route controller is actual controller constructor, it can't just return controller name. It is ngView directive that defines how route controllers are instantiated. Without patching the directive the behaviour can be simulated with:
controller: function ($scope, $controller) {
return $controller('SomeController', { $scope: $scope });
}
In ionic I'm resolving my data with the Ui-Router's resolve functionality before the controller is initialized. As of now I don't have to $inject my EventService into the Controller. The EventService's getEvents() method resolves the data before the controller is initialized. Everything works correctly this way, but now i'm trying to implement the Ion Refresher. I could easily refresh my $scope.events array within the controller, bloating the controller itself, because I would have to $inject the EventService into the controller, and that also means that every controller that uses the same data will have to contain logic to handle a refresh. What is the best way refresh the data outside of the controller or is that the best way?
Events State Definition and data resolution
.state('tab.events', {
url: '/events',
views: {
'tab-event': {
templateUrl: 'views/events.html',
controller: 'EventsController',
resolve: {
events: function (EventService) {
return EventService.getEvents(); //resolves data before ctrl initialized
}
}
}
}
})
Events Controller
(function() {
'use strict'
angular
.module('app.events')
.controller('EventsController', EventsController);
EventsController.$inject = ['$scope','events'];
function EventsController ($scope,events) {
$scope.events = events;
}
}
)();
Bloated Events Controller - Example
(function() {
'use strict'
angular
.module('app.events')
.controller('EventsController', EventsController);
EventsController.$inject = ['$scope','events','EventsService'];
function EventsController ($scope,events,EventsService) {
$scope.events = events;
$scope.refresh = refresh;
function refresh () {
clearCache(); //pretend method
EventsService.getEvents()
.then(function (events) {
$scope.events = events;
$scope.$broadcast('scroll.refreshComplete');
})
}
}
}
)();
Rather than bloating the controller can I refresh this data another way?
call $state.reload() which is an alias for:
$state.transitionTo($state.current, $stateParams, {
reload: true, inherit: false, notify: true
});
This will cause all your states to be "re-entered" which fetches the resolves and re-initializes the controllers.
I wish a hard refresh, which is basically what a $state.reload() does wasn't the answer. I too have this issue and would rather be able to call some method that just forces all the resolved data objects to rerun. The reload causes a page refresh, which causes nasty UI artifacts.
I'm trying to perform a simple test on a helper function I've created:
function getPostId() {
return $stateParams._id;
}
And here is the test I am using, please note that getService is simply a wrapper for the Angular inject() function:
describe('wpApp Router', function() {
var $state, $stateParams, Router;
beforeEach(module('wpApp.core.router'));
beforeEach(function() {
$state = getService('$state');
$scope = getService('$rootScope');
$stateParams = getService('$stateParams');
Router = getService('Router');
$templateCache = getService('$templateCache');
$templateCache.put('/app/sections/posts/list/post-list.html', '');
});
it('should provide the current post ID', function() {
$state.go('posts.details', { _id: 1 });
$scope.$digest();
expect(Router.getPostId()).to.equal(1);
});
});
My router looks like this:
$stateProvider
.state('posts', {
url: '/posts',
controller: 'PostsListController as postsList',
templateUrl: '/app/sections/posts/list/post-list.html'
})
.state('posts.details', {
url: '/:_id',
controller: 'PostDetailsController as postDetails',
templateUrl: '/app/sections/posts/details/post-details.html'
})
I'm trying to set the current state to posts.details with an _id of 1. Then test my helper function to see if it is correctly retrieving the ID.
However, I am getting errors with the templates of the states, like the following: Unexpected request: GET /app/sections/posts/details/post-details.html
The state posts.details is a child of posts and both have their own templates, the problem is I am unable to load both into the templateCache or at least I can't figure out how to do so.
Is it possible to load both templates in order to fulfill the test?
In response to your actual question, the easiest approach to caching templates is by using something like karma-ng-html2js-preprocessor. It will cache all your application templates, and make them available to your tests as a module.
However, from what I can surmise from the code provided, this is un-necessary. Currently, your unit test is actually an integration test in that it's dependent on the routing of the 'posts.details' state in order to pass, and yet the method itself is concerned only with the $stateParams object.
So, instead, as $stateParams is in fact just a plain object, a simpler (and better) approach is just to mock it prior to your test:
beforeEach(module(function($provide) {
$provide.value('$stateParams', {
_id: 1
});
}));
and then you can test your service method in isolation from your states:
it('should provide the current post ID', function() {
expect(Router.getPostId()).toEqual(1);
);
I am using Angular's UI Router and I am looking to create a $scope function (ultimately to pass to the view to have a ng-click call it) to reload a controller and its associated resolver. How would I do this?
I've tried this but it doesn't seem to reload the resolver:
$scope.reloadMe = function() {
$state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true });
};
just inject $route into the controller and call $route.reload so the code would look like:
$scope.reloadMe = function () {
$route.reload();
};
You can read the documentation here: https://docs.angularjs.org/api/ngRoute/service/$route
You can inject $injector and load $state to reload. Here I put two examples, you can use one of them.
function MyController($injector, data) {
$injector.get('$state').reload(); // this reload all states and controllers scopes
// or
$injector.get('$state').go($state.current, {}, {reload: true}); // second parameter is for $stateParams
}
Otherwise, in case i need to reload the page, i use javascript
window.location.reload()
This question is asked here
I am using AngularJS and have implemented routing using it. I want to make sure whenever route changes template is fetched from server and not obtained from cache, is there a way I can force this to happen ?
This should hopefully work:
app.run(function($rootScope, $templateCache) {
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
});
});
According to the comment on the accepted answer, this should be the correct code:
app.run(function($rootScope, $templateCache) {
$rootScope.$on('$viewContentLoaded', function() {
if($templateCache) {
$templateCache.removeAll();
}
});
});