I am using Yeoman's angular-fullstack and am stuck on making multiple views based on Mongo's auto generated _id. The StoreCtlr, which populates all data to the pag,e works well, I am just having trouble passing in the parameter into the StoreShowCtrl
My controller is below:
storeControllers.controller('StoreShowCtrl', ['$scope', '$routeParams','$http',
function($scope, $routeParams, $http) {
$http.get('api/items'+$routeParams.items._id).success(function(detail) {
$scope.data = detail;
});
}
]);
I am routing with
.when('/product/:id', {
templateUrl: 'app/product/product.html',
controller: 'StoreShowCtrl'
});
Thank you for your help!
Use $routeParams.id instead $routeParams.items._id in controller, as you have mentioned id as param while defining state.
This will work.
Related
I have an ASP.NET MVC application with a lot of Areas and models, views and controllers inside them. I have a small calculator that I want to write in Angular because it will be easier for me, as a developer, and cooler for the user (instead of using jQuery only).
The thing is I want to have this calculator on different views in some of my areas in the MVC app. The best solution that I could came up with is make an Angular directive and then use it in every view that I need it. My question is whether this will work and whether I would have to make a different Angular module for every view that will use the directive.
Any better solutions and proposals are welcome.
Example from Angular documentation: https://docs.angularjs.org/tutorial/step_07
phonecatApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: 'PhoneDetailCtrl'
}).
otherwise({
redirectTo: '/phones'
});
}]);
you can config as many controlles that you like per page(html). and each htm will include your custom calculator directive.
All the controllers can be registered to the same module:
var phonecatControllers = angular.module('phonecatControllers', []);
phonecatControllers.controller('PhoneListCtrl', ['$scope', '$http',
function ($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}]);
phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.phoneId = $routeParams.phoneId;
}]);
Here's my take on it: You don't need a separate module per view. If you are only using this to provide your calculator directive then you could just do something like:
angular.module('calculator', [])
.directive('onscreenCalculator', function () { ... });
I don't know if you are using partial views, but if you are it could be problematic if you use the ng-app = "calculator" directive at the view level. Personally, I would put it in your _Layout.cshtml and then you know you're only going to have one instance.
Your biggest challenge (in my opinion) is going to be how to get the result of the calculation back into your view since you're not truly writing an Angular app, but just using a directive. I'm sure it can be done with some playing around, though.
I am using the Angular $routeProvider service to wire-up my single-page HTML5 applciation. I am using the following routing configuration:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/show-order/:orderId', {
templateUrl: 'templates/order.html',
controller: 'ShowOrdersController'
});
}]);
Within the ShowOrdersController I need access to the RESTful URL parameter described above as :orderId. It is suggested that to best achieve this, I should use the $routeParams service in my controller:
app.controller('ShowOrderController', function($scope, $routeParams) {
$scope.order_id = $routeParams.orderId;
});
I have serious concerns about this. My routing logic has now bled through to my controller! If I want to drastically change the routing scheme, I would have to go through all my controller code and correct all the references to $routeParams.
Furthermore, if I want to re-use the ShowOrderController for multiple routes, it's going to enforce all of the routes to use the same token variable :orderId.
This just seems like poor coding to me. It would make more sense to provide some linking mechanism, so the router can specify well-known parameters to the controller.
This would be just like how a modal's resolve method works:
$modal.open({
controller: 'ShowOrderController',
resolve: {
orderId: function () {
return $routeParams.orderId;
}
}
});
app.controller("ShowOrderController", ["orderId", function (orderId, $scope) {
$scope.orderId = orderId;
}]);
Is there any way to achieve this or something similar with the out-of-the-box AngularJS routing services?
As per AngularJS - How to pass up to date $routeParams to resolve? it is possible to reference the current route's parameters in the resolve method of the $routeProvider using $route.current.params:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/show-order/:orderId', {
templateUrl: 'templates/order.html',
controller: 'ShowOrdersController',
resolve: {
orderId: function( $route ) {
return $route.current.params.orderId;
}
}
});
}]);
This will then honour the suggestion above, that the controller can declaratively specify its parameters:
app.controller("ShowOrderController", ["orderId", function (orderId, $scope) {
$scope.orderId = orderId;
}]);
In conjunction, this effectively decouples the controller from the route's parameters.
So I've started to work on an own project, where I'm in the middle of developing the front-end of my website. I started out with an PHP Laravel back-end and I've setted up an API service for my database.
With a hybrid app in mind, i started using angularjs for my front-end web application. For the communication with my API using REST, I've came across restangular, which is pretty nice because it was exactly what I hoped for.
There is only one issue that bothers me, there is no real "guide" how to setup a maintainable module/factory/provider/service to replicate your api with a system that stores the data in local storage or setup simple system where you could inject the "Model" into an controller and just do Model->getAll() to fetching all models.
Because I'm new to angularJS, and therefor my knowedge on how to appeach this, is fairly limited. So far I've made this:
main application
var client = angular.module('clientApp', ['angulartics', 'angulartics.google.analytics', 'ngRoute', 'restangular']);
client.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/', {
controller: 'flongsController',
templateUrl: '/client_partials/Homepage.html'
})
.when('/flongs/:slug', {
controller: 'flongsController',
templateUrl: 'client_partials/Flong.html'
})
.otherwise({
redirectTo: '/'
});
}]);
flongsController
client.controller('flongsController', ['$scope', 'Restangular', '$routeParams', function ($scope, Restangular, $routeParams) {
//controller variables
var baseFlongs = Restangular.all('flongs');
$scope.flongs = {};
init();
function init() {
baseFlongs.getList().then(function(flongs){
$scope.flongs = flongs;
});
}
}]);
So, my question is simple:
How can i improve this code so that its more efficient and more maintainable?
Thanks in advance,
Nick van der Meij
First of all do not use service logic on the controller, instead use angular services for this purpose.
Let me share you how I build my projects,
First build Restangular Service :
angular.module('example').factory('exampleService', ['Restangular', function(Restangular){
// this is service object with list of methods in it
// this object will be used by controller
var service = {
getExamples: getExamples,
getExample: getExample
};
// get examples from server by using Restangular
function getExamples(){
return Restangular.all('examples').getList();
}
// get example with given id from server by using Restangular
function getExample(exampleId){
return Restangular.one('examples', exampleId).get();
}
return service;
}]);
here we build exampleService now let's inject it into a controller
angular.controller('ExampleCtrl', ['exampleService', function(exampleService){
// get examples by using exampleService
exampleService.getExamples().then(function (examples) {
$scope.examples = examples;
});
// get example with given id by using exampleService
exampleService.getExample('1234').then(function (example) {
$scope.example = example;
});
}]);
This is how I use it basically. For more advanced usage you can look the examples in Restangular Github Page.
I have a simple problem that I can't seem to figure out. I am new to angular.js and am trying ui.router. My web application is a table that displays JSON data.
The columns are all of the keys in a single JSON object, and the rows are the values for each respective key. I would like to do something like the following:
go to www.xyz.com/keyname,
and see all of the values for keyname.
However, I got stuck in trying to get the keys.
The keys are defined in a controller which is passed the data via a factory. I was then thinking I would do something like this:
var app = angular.module('SortingTables', ['ui.bootstrap', 'ui.router']);
app.factory('dataTable', function () {
return tastyJSONData;
});
app.controller('Ctrl', ['$scope', 'dataTable', function ($scope, dataTable) {
$scope.dataTable = dataTable;
$scope.columns = the keys in dataTable;
}]);
app.config(['$stateProvider', '$urlRouterProvider',function ($stateProvider,$urlRouterProvider) {
// pseudocode
for every column in $scope.columns in Ctrl
$stateProvider.state(column)...
}]);
However, I can't access the scope within the controller which contains the data. Am I missing something?
The config runs before the factory, so how can I access the data made by the factory in my config?
I believe it is best practice to keep all logic within the controller. Maybe go for something along the lines of:
app.controller('Ctrl', ['$scope', '$stateProvider', 'dataTable', function ($scope, $stateProvider, dataTable) {
$scope.dataTable = dataTable;
$scope.columns = the keys in dataTable;
// pseudocode
for every column in $scope.columns
$stateProvider.state(column)...
}]);
And then just leave your config for routing purposes
app.config(['$urlRouterProvider',function ($urlRouterProvider) {
//routing
}]);
Hard to say for sure without complete code. Hope this helps!
I think defining explicit states is making things harder than is required.
Try something like this:
.state('keys', {
url: '/',
resolve: {
keys: ['$http', function($http {
return $http.get('/api/keys');
}]
},
controller: function($scope, keys) {
$scope.allKeys = keys;
}
})
.state('keys.detail', {
url: '/:keyname',
controller: function($scope, $stateParams) {
$scope.keyname = $stateParams.keyname;
}
})
and in your view for 'keys' state something like:
<li ng-repeat="keyname in allKeys">
<a ui-sref="keys.detail({keyname: keyname})">{{ keyname }}</a>
</li>
I've been experimenting a little with Angular.js lately. As part of this I created a very simple set of controllers with an ng-view and templates to trigger depending on the route requested. I'm using angularFireCollection just to grab an array from Firebase. This works fine in the thumbnailController which does not form part of the ng-view.
My problem is that in addition to the data flowing into the thumbnailController, I also need the two other controllers to be able to access the data. I initially simply set the data to either be part of $rootScope or to have the ng-view as a child of the div in which the thumbnailController is set.
However, the issue from that perspective is that each sub-controller presumably attempts to set the data in the template before it is actually available from Firebase.
The solution appears to be using resolve as per the answer to this question angularFire route resolution. However, using the below code (and also referencing angularFireCollection) I get an error message of angularFire being an unknown provider. My understanding is the code below should be sufficient, and I would also add that the usage of angularFireCollection in thumbnailController works fine as I say.
I also experimented with injecting angularFire/aFCollection directly into the controllers using .$inject however a similar issue arose in terms of it being considered an unknown provider.
If possible could someone advise on what the issue may be here?
var galleryModule = angular.module('galleryModule', ['firebase']);
galleryModule.config(['$routeProvider', 'angularFire', function($routeProvider, angularFire){
$routeProvider.
when('/', {
controller: initialController,
templateUrl: 'largeimagetemplate.html',
resolve: {images: angularFire('https://mbg.firebaseio.com/images')}
}).
when('/view/:id', {
controller: mainimageController,
templateUrl: 'largeimagetemplate.html',
resolve: {images: angularFire('https://mbg.firebaseio.com/images')}
}).
otherwise({
redirectTo: '/'
});
}]);
galleryModule.controller('thumbnailController', ['$scope', 'angularFireCollection', function($scope, angularFireCollection){
var url = 'https://mbg.firebaseio.com/images';
$scope.images = angularFireCollection(url);
}]);
function initialController($scope,images){
$scope.largeurl = images[0].largeurl;
}
function mainimageController($scope, images, $routeParams){
$scope.largeurl = images[$routeParams.id].largeurl;
}
I got the chance to dig into this a little bit - it seems like regular services cannot be used in .config sections. I'd instantiate angularFire in the controller instead of using resolve, for example:
galleryModule
.value("url", "https://mbg.firebaseio.com/images")
.controller('thumbnailController', ['$scope', 'angularFireCollection', 'url',
function($scope, angularFireCollection, url) {
$scope.images = angularFireCollection(url);
}])
.controller('initialController', ['$scope', 'angularFire', 'url',
function($scope, angularFire, url) {
angularFire(url, $scope, 'images').then(function() {
$scope.largeurl = $scope.images[0].largeurl;
});
}])
.controller('mainimageController', ['$scope', 'angularFire', '$routeParams', 'url',
function($scope, angularFire, $routeParams, url){
angularFire(url, $scope, 'images').then(function() {
$scope.largeurl = $scope.images[$routeParams.id].largeurl;
});
}]);
This is not ineffecient, since the data is only loaded once from the URL by Firebase, and all subsequent promises will be resolved almost immediately with data already at hand.
I would like to see angularFire work with resolve in the $routeProvider, however. You can use this method as a workaround until we figure out a more elegant solution.