Can someone help me unravel this mystery.
My first $resource return a list.
Then, i loop through the list and call another $resource for each object in the collection.
This code was working using $http, but I was told i should be using the $resource for restful and there u go, I am stuck.
I am getting error : AngularJS Object # has no method 'push'
My restful service returns a JSON object:
In my service/factory :
services.factory('XXXXFactory', function ($resource) {
return $resource('/xxxx-webapp-1.0-SNAPSHOT/restful/services/XXXOption/actions/listAll/invoke', {}, {
query: { method: 'GET', isArray: true },
create: { method: 'POST' }
})
});
In my controller :
app.controller('XXXXListCtrl', ['$scope', 'XXXXsFactory', 'XXXXXFactory', '$location',
function ($scope, XXXXsFactory, XXXXXFactory, $location) {
XXXXsFactory.query(function(data) {
// success handler
var resultType = data.resulttype;
var objects = data.result.value;
$scope.rowList= [];
console.log(objects);
alert('list? = '+ resultType);
if(resultType == "list"){
angular.forEach(objects, function (item) {
alert('item href = '+ item.href);
var InnerXXXXResource = $resource(item.href, {}, { query: { method: 'GET', isArray: true}});
InnerXXXXResource .query(function(rowdata) {
$scope.rowList.push(rowdata);
}, function(error) { });
});
}
}, function(error) {
// error handler
});
}]);
HTML:
<tbody>
<tr ng-repeat="row in rowList">
<td width="70%">{{row.members.XXXDescription.value}}</td>
<td align ="center" width="30%">{{row.members.price.value}}</td>
</tr>
</tbody>
If you want to post data to server and client:
So, in your controller you should get the data using your Factory
$scope.data = XXXXFactory.query();
And if you are dealing with objects change isArray: false
and Posting the data to sever
$scope.createInventory = function(){
XXXXFactory.create($scope.newdata); // posts data to server side
$scope.data.objects.push($scope.newdata); //posts data to client side
$scope.newdata = '';
};
Related
This is an app that I took over from another developer. I have a controller that calls a function inside a service and it passes in the $scope of the controller as a parameter. THis exact same thing is done with another function in the service.
THe problem is that only one of these services seem to update the view.
Here is my code (very condensed to keep it short, or a short as possible)
var KrisisEventsApp = angular.module('KrisisEventsApp', []);
KrisisEventsApp.filter('unsafe', function ($sce) { return $sce.trustAsHtml; });
//Controller for registration
KrisisEventsApp.controller('RegistrationCtrl',
['$scope', 'RegistrationService', '$timeout',
function ($scope, RegistrationService, $timeout) {
$scope.SaveRegistrantData =
function () {
//save user input
RegistrationService.SaveRegistrationForm($scope);
};
$scope.Products_Continue =
function () {
RegistrationService.ListItemsForCart($scope);
};
}
]
);
KrisisEventsApp.service('RegistrationService',
['$http', function ($http) {
var thisService = this;
//injects custom properties into registration form
thisService.SaveRegistrationForm = function ($scope) {
this.count = 0;
this._scope = $scope;
// if no product are found, go straight to payment page
this.count = Object.keys($scope.products).length;
// console.log(this.count);
$http({
method: "POST",
url: v_ModulePath + "/API/Registrants_WebAPI/RegisterUser",
dataType: 'text/plain',
data: data,
headers: {
'Content-Type': 'text/plain',
'ModuleId': v_servicesFramework.getModuleId(),
'TabId': v_servicesFramework.getTabId(),
'RequestVerificationToken': v_servicesFramework.getAntiForgeryValue()
}
})
.then(function (response) {
data = JSON.parse(JSON.parse(response.data))
this.config2 = {
method: "GET",
url: v_ModulePath + "/API/Registrants_WebAPI/ListItemsForCart?idregistrant=" + $("#hid_registrant_id").val() + "&idevent=" + v_EventID,
dataType: 'text/plain',
data: '',
headers: {
'Content-Type': 'text/plain',
'ModuleId': v_servicesFramework.getModuleId(),
'TabId': v_servicesFramework.getTabId(),
'RequestVerificationToken': v_servicesFramework.getAntiForgeryValue()
}
}
return $http.get(v_ModulePath + "/API/Registrants_WebAPI/ListItemsForCart?idregistrant=" + $("#hid_registrant_id").val() + "&idevent=" + v_EventID, this.config2);
})
.then(function (response) {
data = JSON.parse(JSON.parse(response.data));
$scope.Cart = data;
});
}
//list cart items
thisService.ListItemsForCart = function ($scope) {
$http(
{
method: "GET",
url: v_ModulePath + "/API/Registrants_WebAPI/ListItemsForCart?idregistrant=" + $("#hid_registrant_id").val() + "&idevent=" + v_EventID,
dataType: 'text/plain',
data: '',
headers: {
'Content-Type': 'text/plain',
'ModuleId': v_servicesFramework.getModuleId(),
'TabId': v_servicesFramework.getTabId(),
'RequestVerificationToken': v_servicesFramework.getAntiForgeryValue()
}
}).success(function (data) {
data = JSON.parse(JSON.parse(data));
$scope.Cart = data;
}).error(function (data) {
});
}
}
]
);
Here is the view (portion):
...
<a ng-click="SaveRegistrantData()" class="small button success" id="but_InputForm_MoveNext">Continue</a>
...
<a ng-click="Products_Continue()" class="small button success">Continue</a>
...
<tbody>
<tr ng-repeat="CartItem in Cart.Cart_Items_List">
<td>{{ CartItem.Item_Description }}</td>
<td class="text-right">{{ CartItem.Item_Fee }}</td>
</tr>
<tr>
<td>Total to Pay</td>
<td class="text-right">{{ Cart.CartTotal }}</td>
</tr>
</tbody>
You can see that the SaveRegistrationForm and ListItemsForCart functions are called from the controller, which are in turn initiated by button clicks from the view.
NOTE:
the following lines are the important ones in each function:
data = JSON.parse(JSON.parse(response.data));
$scope.Cart = data;
PROBLEM:
Only the ListItemsForCart updates the view, when I run the SaveRegistrationForm function the view does not update.
I have used fiddler to examine the web api calls and both functions successfully return the same data.
I have also used the chrome console to confirm that the $scope.Cart object does in fact get assigned the right data.
QUESTION:
Can someone help me figure out why my view is not updating?
Okay, I inherited this app from another developer. They defined the controller with the same name twice in the html view. arrrrg. So the second set of data that was not updating was in the second instance of the controller.
Once I moved a single controller instance to wrap the whole view the problems all went away.
Thanks to all who helped. You would not have been able to tell this from the abbreviated view code I posted. (I also have many other things to update, like .success to then catch and like Satpal said: just returning promises from my services etc...)
Created an Angular Service:
calculator_app.service('FillOpportunity', function () {
this.fill_opportunity = function (path,scope) {
$.ajax({
url: 'opportunitycalculator/calculator/GetProducts?idstring=' + path,
type: "GET",
cache: false,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data)
{
scope.opportunity_data = data;
scope.$apply();
},
error: function () {
}
});
};
});
Called the service on ng-change of a dropdown:
FillOpportunity.fill_opportunity($scope.result_path,$scope);
The scope.opportunity_data is binded to the select in UI:
<select id="seloppurtunityproducts" name="selproducttype" multiple="" style="height:300px" ng-model="opportunity_products" ng-options="a for a in opportunity_data"></select>
On ng-Change, Ajax is called when I check in Network of Chrome, but the value is not updated in the select box.
Any inputs?
Don't use jQuery's ajax. Use the built in $http. Using $http automatically begins the digest cycle of angular's builtin compiler. If you must use jquery... then you'd have to call $scope.$apply(); every time there is a data change.
Service:
calculator_app.factory("calcService", ["$http", function($http) {
return {
getItem: function(url, items) {
return $http.get(url,
// query string like { userId: user.id } -> ?userId=value
{ params: items });
}
}
}]);
Inject the service into your controller and use:
calculator_app.controller("MainCtrl", ["calcService", "$scope", function(calcService, $scope) {
$scope.opportunity_data = [];
var payload = {
idstring: path
};
//call the service
calcService.getItem('path/to/calc/api', payload).then(function(response) {
$scope.opportunity_data = response.data;
}).catch(function(response) {
alert('error' + response.data);
});
}]);
I'm using Angular in an application. After getting a specific object (a movie in my case), I'm assigning the object to $scope ($scope.movie = response), so that I can use it in the view. The problem is that my view seems not to display anything I use in $scope. I've tried deleting everything and doing a dummy test like $scope=name="whatever" and when I use something like {{name}} in the view nothing is rendered. Have anyone faced this problem ? I've already searched for this error, and it seems like it would be a good idea to use $apply(). I've tried that and it didn't work. The function that fetches the data is below:
var app = angular.module('movies');
app.factory('Films', ['$resource',function($resource){
return $resource('/films.json', {},{
query: { method: 'GET', isArray: true },
create: { method: 'POST' }
})
}]);
app.factory('Film', ['$resource', function($resource){
return $resource('films/:id.json', {}, {
show: {method: 'GET' },
update: { method: 'PUT', params: {id: '#id'} },
delete: { method: 'DELETE', params: {id: '#id'} }
});
}]);
app.controller('MoviesController', ['$scope', '$http', '$location', '$resource', '$routeParams', 'Films', 'Film', function($scope, $http, $location, $resource, $routeParams, Films, Film){
$scope.movies = Films.query();
$scope.user = document.getElementById('name').innerHTML; // Find a better way to interact with devise via angular
$scope.createMovie = function() {
$scope.movies = Films.query();
$http.get(
'/categories.json'
).success(function(data,status,headers,config){
$scope.categories = data;
}).error(function(data, status, headers, config){
alert("There was an error while fetching the categories on the database. Error " + status);
});
$location.path("/" + 'new').replace();
};
$scope.listMovies = function() {
$location.path("/").replace();
};
$scope.save = function(){
if($scope.form.$valid){
Films.create({film: $scope.movie}, function(){
$scope.form.$setPristine();
}, function(error){
alert("Movie not created");
});
}
};
$scope.deleteMovie = function(movie){
Film.delete(movie);
$scope.movies = Films.query();
};
$scope.viewDetails = function(movie){
$scope.name="ola";
alert(movie.id);
$location.path("/" + movie.id);
var Movie = $resource('films/:filmId'+'.json', {filmId: '#id'});
$scope.movie = Movie.get({filmId: movie.id});
$scope.movie.$promise.then(
function(response){
$scope.$apply();
$scope.movie = response;
console.log("filme e: " + response.name);
},
function(error){
console.log("request failed");
}
);
};
}]);
I had a look at your repository and I think where your problem is. You are trying to reuse the MoviesController in all of your routes. But AngularJS will create a new instance for every route and therefore you can't access your previous data because it will be destroyed.
So I would start by creating a separated controller for each view, so you can move the code of your viewDetails method to a new MovieDetailController. To have access to the movie id in this controller, you need to use the $routeParams service.
angular.module('movies').controller('MovieDetailController', MovieDetailController);
function MovieDetailController($scope, $resource, $routeParams) {
var Movie = $resource('films/:filmId'+'.json', {filmId: '#id'});
Movie.get({filmId: $routeParams.id}).then(
function(response) {
$scope.movie = response;
},
function(error){
console.log('request failed');
}
);
}
Change your route definition to use the new controller.
.when('/movies/:id', {
controller: 'MovieDetailController',
templateUrl: 'movie_details.html'
})
And now your viewDetails method in the MoviesController just need to redirect to the movie detail url.
$scope.viewDetails = function(movie) {
$location.path('/movies/' + movie.id);
}
I hope it works for you. Let me know when you try!
I ve got an angular resource service which then returns the data to a controller and I get all the data plus the data by name.
My application works just fine in the browser but I get a resource error in the console. Bad resource configuration.
I had a look in various questions and everyone states that I need to set the configuration property isArray to either false or true.
I have tried to do this but I still get an error.
Any ideas much appreciated.
Here is my service :
(function() {
var app = angular.module('test');
app.service('ContactResource', function($resource) {
return $resource('/contacts/:firstname', {},
{'update': {method: 'PUT'}},
{'query': { method: 'GET', isArray: true }},
{'get': { method: 'GET', isArray: false }}
);
});
}());
And here is my controller:
(function() {
var app = angular.module('test');
app.controller('contactsCtrl', function($scope, $routeParams, ContactResource) {
$scope.contacts = ContactResource.query();
$scope.singlecontact = ContactResource.get({firstname: $routeParams.firstname});
});
}());
The error I am getting is : Error: [$resource:badcfg] http://errors.angularjs.org/1.4.2/$resource/badcfg?p0=get&p1=object&p2=array&p3=GET&p4=%2Fcontacts
When I click it says :
Error in resource configuration for action get. Expected response to contain an object but got an array (Request: GET /contacts)
When I get the url is /contacts the response is :
[{EmailAddress:some#email.com, etc}]
When the url is /contacts/firstname the response is :
{EmailAddress:some#email.com,etc}
I solved the problem by adding a new controller called single controller and by separating the service into two functions. Here is how my code looks like now.
This is the service:
(function() {
var app = angular.module('test');
app.service('ContactResource', function($resource, $routeParams) {
this.all = function() {
return $resource('/contacts', {},
{'query': { method: 'GET', isArray: true }}
)};
this.single = function() {
return $resource('/contacts/:firstname', {firstname: '#firstname'},
{'query': { method: 'GET', isArray: false }}
);
}
});
}());
And the controllers :
(function() {
var app = angular.module('test');
app.controller('contactsCtrl', function($scope, $routeParams, ContactResource) {
$scope.contacts = ContactResource.all().query();
});
app.controller('singleCtrl', function($scope, $routeParams, ContactResource) {
$scope.singlecontact = ContactResource.single().query({firstname: $routeParams.firstname});
});
}());
For some reason which I am still not sure $resource wouldn't accept them into the same controller.
How to make angularjs $resource return an array of objects derived/prototyped from specified domain object?
Here is an example on http://plnkr.co/edit/AVLQItPIfoLwsgDzoBdK?p=preview that processes a set of Notes objects.
app.controller('MainCtrl', function($scope, NoteResource) {
$scope.name = 'World';
$scope.notes = NoteResource.query();
$scope.spellCheckAllNotes = function() {
angular.forEach($scope.notes, function(note) {
note.spellCheck();
});
}
});
The issue is that $resource returns array of Resources and not an array of Notes with Resource methods added to prototypes.
[solution shall follow "good" javascript practices]
Here is the completed plunker. Yes raw json is parsed to JSON object. It is using transformResponse as mentioned by Armando.
app.factory('NoteResource', ['$resource',
function($resource) {
var res = $resource('http://okigan.apiary.io/notes/:id', {}, {
query: {
method: 'GET',
params: {
},
isArray: true,
transformResponse: function(data, header){
//Getting string data in response
var jsonData = JSON.parse(data); //or angular.fromJson(data)
var notes = [];
angular.forEach(jsonData, function(item){
var note = new Note();
note.noteTitle = item.title;
notes.push(note);
});
return notes;
}
}
});
return res;
}
]);
Just to show title is not used from the raw resource, I modified title to noteTitle in Note and in html.
You can manipulate your data using transformResponse option in your resource service definition (make sure to set isArray to true):
angular.module('services', ['ngResource']).
factory("yourService", function ($resource) {
return $resource(
'/custom/url', {}, {
get: {
method: 'GET',
isArray: true,
transformResponse: function(data, headers){
//
// transform to array of objects
return data;
}
}
}
);
});