I am having trouble getting resolve in $routeProvider to automatically update the view.
I am trying to convert an example (chapter 22) in Adam Freeman's Pro Angular book from Deployd to Express-Mongo. A possible hint is that the automatic refresh works using a local version of Deployd. When I switched to local Express and Mongo backend (after making the id to _id changes), the automatic view update no longer works.
When using Express-Mongo, I have to manually execute $route.reload() function to get show the updated changes from the database. I am new to angular so any hints are appreciated.
This heavy handed Delete works:
$scope.deleteProduct = function (product) {
product.$delete();
$route.reload();
$location.path("/list");
}
The below version Doesn't work. I was under the (probably mistaken) impression that the 'resolve' property in $routeProvider updates the view when the data is returned. With the below code, I get a Type Error: Undefined is not a function
$scope.deleteProduct = function (product) {
product.$delete().then(function () {
$scope.data.products.splice($scope.data.products.indexOf(product), 1);
});
$location.path("/list");
}
Console Log Errors
TypeError: undefined is not a function
at http://localhost:8080/bower_components/angular-resource/angular-resource.js:530:25
at Array.forEach (native)
at forEach (http://localhost:8080/bower_components/angular/angular.js:302:11)
at angular.module.factory.Resource.(anonymous function).$http.then.value.$resolved (http://localhost:8080/bower_components/angular-resource/angular-resource.js:529:17)
at deferred.promise.then.wrappedCallback (http://localhost:8080/bower_components/angular/angular.js:10905:81)
at deferred.promise.then.wrappedCallback (http://localhost:8080/bower_components/angular/angular.js:10905:81)
at http://localhost:8080/bower_components/angular/angular.js:10991:26
at Scope.$get.Scope.$eval (http://localhost:8080/bower_components/angular/angular.js:11906:28)
at Scope.$get.Scope.$digest (http://localhost:8080/bower_components/angular/angular.js:11734:31)
at Scope.ng.config.$provide.decorator.$delegate.__proto__.$digest (<anonymous>:844:31) angular.js:9383
Below is the code for the module
angular.module("exampleApp", ["ngResource", "ngRoute"])
.constant("baseUrl", "http://localhost:8080/api/products/")
.factory("productsResource", function ($resource, baseUrl) {
return $resource(baseUrl + ":id", { id: "#_id" },
{
create: { method: "POST" , isArray: true },
save: { method: "PUT", isArray: true },
delete: {method: "DELETE", isArray: true},
update: {method: "PUT", isArray: true},
query: {method: "GET", isArray: true}
})
})
.config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
...
$routeProvider.otherwise({
templateUrl: "/views/tableView.html",
controller: "tableCtrl",
resolve: {
data: function (productsResource) {
return productsResource.query();
}
}
});
})
.controller("defaultCtrl", function ($scope, $location, productsResource, $route) {
$scope.data = {};
$scope.deleteProduct = function (product) {
product.$delete().then(function(products) {
//Success
console.log("Success"); //Don't Get Here
$scope.data.products.splice($scope.data.products.indexOf(product), 1);
}, function(errResponse) {
//Failure (Code Produces a Type Error: Undefined is not a function)
console.log("Error: " + errResponse);
});
$location.path("/list");
}
})
The Table View Controller that is bound to the $routeProvider.otherwise
.controller("tableCtrl", function ($scope, $location, $route, data) {
$scope.data.products = data;
$scope.refreshProducts = function () {
$route.reload();
} })
I think you should redirect when the delete is complete:
$scope.deleteProduct = function (product) {
product.$delete().then(function () {
$scope.data.products.splice($scope.data.products.indexOf(product), 1);
$location.path("/list");
});
}
You have missed } at the and of line with text:
delete: {method: "DELETE", isArray: true
Related
I have an usual AngularJS Controller:
controllers.UController = function ($scope, uFactory) {
$scope.data1 = uFactory.getDataUsingAjax1();
$scope.data2 = uFactory.getDataUsingAjax2();
$scope.data3 = uFactory.getDataUsingAjax3();
...
}
The mentioned fields (data1 - data3) gets populated using Ajax call.
I also have several Views.
When I run my app the first time, I can see all the 3 Ajax calls in order to populate data1-data3.
But every time I redirect to another View, I can see that this population starts again and again.
In my understanding it's not really a SPA architecture or it's a bad SPA.
Is this how it should work or I am missing something?
Here are the details:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/',
{
controller: 'UController',
templateUrl: '/Partial/View1.html'
})
.when('/View2',
{
controller: 'UController',
templateUrl: '/Partial/View2.html'
})
.otherwise({ redirectTo: '/View3' });
}]);
myApp.factory('uFactory', function () {
var factory = {};
data1 = [];
data2 = [];
factory.getAjaxData1 = function () {
$.ajax({
url: url,
type: 'GET',
contentType: "application/json",
async: false,
success: function (result) {
data1= result;
}
});
return data1;
}
factory.getAjaxData2 = function () {
$.ajax({
url: url,
type: 'GET',
contentType: "application/json",
async: false,
success: function (result) {
data2= result;
}
});
return data2;
}
}
var controllers = {};
controllers.uController = function ($scope, $location, uFactory) {
$scope.data1 = uFactory.getAjaxData1();
$scope.data2 = uFactory.getAjaxData2();
}
Redirection is done by href link:
a href="#/View1"Do it/a
I am creating a new angular App and using factory but when i am am getting an error which is
Error: [$injector:undef] http://errors.angularjs.org/1.4.5/$injector/undef?p0=Data
at Error (native)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:6:416
at Object.$get (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:37:32)
at Object.e [as invoke] (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:39:96)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:40:410
at d (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:38:308)
at e (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:39:64)
at Object.g.instantiate (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:39:213)
at b.$get (https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js:80:257)
at s (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular-route.min.js:12:165)
var app = angular.module('testapp', ['ngRoute']);
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/userlist', {
title: 'List of all the users',
templateUrl: 'userlist.html',
controller: 'listuser'
})
.when('/profile',{
title:'user detail page',
templateUrl:'profile.html',
controller:'listuser'
})
.otherwise({
redirectTo: '/userlist'
});
}])
app.factory("Data", ['$http','$log',
function ($http,$log) {
var obj = {};
obj.post = function (q, object) {
return $http({
method: 'POST',
url:'userdetail.php',
data: object.user
})
.then(function (results) {
$log.log(results);
return results.data;
});
};
}]);
app.controller('listuser',['Data', function ($scope,$http,$log,$window,Data) {
$scope.userdetail = {};
var init = function () {
$http({
method: 'POST',
url: 'apisource.php',
})
.then(function (results) {
$scope.data=results.data;
});
};
init();
$scope.douserdetail = function(user) {
Data.post({
user: user
}).then(function (results) {
if (results.status == "success") {
//$location.path('dashboard');
}
});
};
}]);
Factory functions in angular are expected to return an object, but your "Data" factory does not return anything. Simply add the following at the end of your factory function to fix the issue:
return obj;
Have a look at the link provided in your stacktrace. Your factory has to return a value:
app.factory("Data", ['$http','$log',
function ($http,$log) {
var obj = {};
...
return obj;
}]);
There are many error, in controller your are using $http, what is the purpose
You are calling init() inside the init which will cause the infinite loop
You service is not returning anything
I will suggest to check the basics angular first
I am using angular-ui-router's resolve to get data from server before moving a state. I want to inform user if the request has failed. I have service that will response error the request has failed. My question is how can I detect the failure in ui-router resolve and trigger some Modal service like pop up.
I have read some related posts online, but I am still confused how to make it happen. Thanks in advanced!
Config and Service:
angular.module('myApp',['ui.router', 'ngAnimate', 'ui.bootstrap'])
.config(function ($stateProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$stateProvider
.state('customer', {
url: '/customer',
templateUrl: '/customer.html',
controller: 'CustomerCtrl',
resolve: {
/*
* How to inject CustomerService here
* How to catch the server error
* How to trigger a popup
*/
data: cusomter_data
}
});
})
.service('CustomerService', function($http, $q) {
return ({
getGeneral: getGeneral
});
function getGeneral(customer_id) {
var request = $http({
method: "get",
url: '/customer',
params: {
customer_id: customer_id
}
});
return (request.then( handleSuccess, handleError));
}
function handleError (response){
if (!angular.isObject(response.data) || !response.data.message) {
return($q.reject("Failed to retrieve customer information."));
}
return($q.reject(response.data.message));
}
function handleSuccess(response) {
return (response.data);
}
});
After some research, I found out a solution by creating a errorModal service and inject it to resolve. Here is my solution.
$stateProvider
.state('customer', {
url: '/customer',
templateUrl: '/customer.html',
controller: 'CustomerCtrl',
resolve: {
data: function(CustomerService, SelectedCustomerService, errorModalService) {
var shared = SelectedCustomerService;
return CustomerService.getData(shared.customerid).then(
function (data) { return data; },
function(error) {
var modalOptions = {
closeButtonText: 'Close',
headerText: 'Customer Error',
bodyText: error
};
errorModalService.showModal({}, modalOptions);
}
);
}
}
});
I am trying to build my first Angular $resource to give my application access to CRUD operations, but for some reason the actions being configured for the resource are not defined when I try to execute a query.
Here is my controller logic:
app.controller('MainCtrl', function ($scope, $http, $resource) {
var Alert = $resource('/WebApi/Alert/:type/:id',
{
systemUpdate: { method: 'GET' },
autoArchive: { method: 'POST', url: '/WebApi/Alert/Template/:type' }
});
$scope.systemUpdate = function (alert) {
var data = Alert.systemUpdate({ type: alert.Status, id: alert.AlertId }); // THIS LINE FAILS
console.log(data);
}
I get an error saying that Alert.systemUpdate is not defined. Am I doing something wrong here when configuring my $resource?
Change the definition of your Alert to
var Alert = $resource('/WebApi/Alert/:type/:id',
{},
{
systemUpdate: { method: 'GET' },
autoArchive: { method: 'POST', url: '/WebApi/Alert/Template/:type' }
});
As mentionned in the documentation of $resource, the order of the parameters is the following:
1) Url
2) The default value of the parameters of the url, since you don't have any default value, you must provide an empty object
3) The actions (systemUpdate & autoArchive here)
I am having a heck of a time trying to figure out why I'm getting the Unknown provider error in Angular. I've checked every other question I could find on the subject and most suggest an error in dependency injection. However, it doesn't seem to me like I'm forgetting to inject anything. I've been trying to get the resolve property to work like this post by Misko. I'm able to console log out the employee data after it's resolved, but then I get the Unknown provider error, which prevents the data from being shown on the page.
Here is my router:
"use strict";
var app = angular.module('app',[
'employeeServices'
]);
app.config(appRouter);
function appRouter ($routeProvider) {
$routeProvider
.when('/employees/:account_id', {
controller: 'EmployeeCtrl',
templateUrl: 'view/employee/view.html',
resolve: employeeCtrl.resolve
})
.otherwise({ redirectTo: '/' });
}
Here is my controller
var employeeCtrl = app.controller('EmployeeCtrl', [
'$scope',
'employees',
function ($scope, employees) {
$scope.employee = employees;
console.log($scope.employee);
}
]);
employeeCtrl.resolve = {
employees: function (Employee, $q, $route) {
var deferred = $q.defer();
console.log("current params: ", $route.current.params.account_id);
Employee.getOne({ id: $route.current.params.account_id }, function (successData) {
deferred.resolve(successData);
}, function (errorData) {
deferred.reject(errorData);
});
return deferred.promise;
}
};
And my factory:
angular.module('employeeServices', ['ngResource'])
.factory('Employee', ['$resource', function ($resource) {
return $resource('/employees/:id/json',
{
id: '#account_id'
},
{
'save': {
method: 'POST',
isArray: false
},
'update': {
method: 'PUT',
params: {
id: '#account_id'
}
},
'remove': {
method: 'DELETE',
params: {
id: '#account_id'
}
},
'getOne': {
method: 'GET',
params: {
id: '#account_id'
},
isArray: false
},
'query': {
method: 'GET',
params: {
id: '#account_id'
},
isArray: true
}
}
);
}]);
Any suggestions would be so greatly appreciated!
So the problem was that I was setting up the EmployeeCtrl controller through ng-controller inside my partial's view, like so:
<div class="viewPage" ng-controller="EmployeeCtrl">
When using resolve, however, the controller set up must be done through the router in order for it to be available at runtime. I removed the ng-controller="EmployeeCtrl...
<div class="viewPage">
... and presto, like nothing ever happened.
I have to note that I received help from the kind, patient folks over on the AngularJS IRC channel...
Since you defined the factory called Employee, you should use the exact name to refer to this module when you inject it to the controller.
var employeeCtrl = app.controller('EmployeeCtrl', [
'$scope',
'employees',
Change to
var employeeCtrl = app.controller('EmployeeCtrl', [
'$scope',
'Employee',