content is loading everytime I refresh the page - javascript

I'm developing a simple CRUD application with MEAN stack. So the scenario is a user post a data to the server and it will render the data in real-time. Everything works fine but whenever I refresh the page ,
It will sort of loads all the content, every time it tries to fetch the data. I guess this is a caching problem.
So what I want to achieve is, every time a user refresh the page or go to another link, the content will be there without waiting for split seconds.
Here's the link to test it on, try to refresh the page
https://user-testing2015.herokuapp.com/allStories
and the code
controller.js
// start our angular module and inject our dependecies
angular.module('storyCtrl', ['storyService'])
.controller('StoryController', function(Story, $routeParams, socketio) {
var vm = this;
vm.stories = [];
Story.all()
.success(function(data) {
vm.stories = data;
});
Story.getSingleStory($routeParams.story_id)
.success(function(data) {
vm.storyData = data;
});
vm.createStory = function() {
vm.message = '';
Story.create(vm.storyData)
.success(function(data) {
// clear the form
vm.storyData = {}
vm.message = data.message;
});
};
socketio.on('story', function (data) {
vm.stories.push(data);
});
})
.controller('AllStoryController', function(Story, socketio) {
var vm = this;
Story.allStories()
.success(function(data) {
vm.stories = data;
});
socketio.on('story', function (data) {
vm.stories.push(data);
});
})
service.js
angular.module('storyService', [])
.factory('Story', function($http, $window) {
// get all approach
var storyFactory = {};
var generateReq = function(method, url, data) {
var req = {
method: method,
url: url,
headers: {
'x-access-token': $window.localStorage.getItem('token')
},
cache: false
}
if(method === 'POST') {
req.data = data;
}
return req;
};
storyFactory.all = function() {
return $http(generateReq('GET', '/api/'));
};
storyFactory.create = function(storyData) {
return $http(generateReq('POST', '/api/', storyData));
};
storyFactory.getSingleStory = function(story_id) {
return $http(generateReq('GET', '/api/' + story_id));
};
storyFactory.allStories = function() {
return $http(generateReq('GET', '/api/all_stories'));
};
return storyFactory;
})
.factory('socketio', ['$rootScope', function ($rootScope) {
var socket = io.connect();
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
},
emit: function (eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
});
}
};
}]);
api.js (both find all object and single object)
apiRouter.get('/all_stories', function(req, res) {
Story.find({} , function(err, stories) {
if(err) {
res.send(err);
return;
}
res.json(stories);
});
});
apiRouter.get('/:story_id', function(req, res) {
Story.findById(req.params.story_id, function(err, story) {
if(err) {
res.send(err);
return;
}
res.json(story);
});
});
For api.js whenever I refresh the page for '/all_stories' or go to a '/:story_id' it will load the data for split seconds.
allStories.html
<div class="row">
<div class="col-md-3">
</div>
<!-- NewsFeed and creating a story -->
<div class="col-md-6">
<div class="row">
</div>
<div class="row">
<div class="panel panel-default widget" >
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span>
<h3 class="panel-title">
Recent Stories</h3>
<span class="label label-info">
78</span>
</div>
<div class="panel-body" ng-repeat="each in story.stories | reverse" >
<ul class="list-group">
<li class="list-group-item">
<div class="row">
<div class="col-xs-10 col-md-11">
<div>
<div class="mic-info">
{{ each.createdAt | date:'MMM d, yyyy' }}
</div>
</div>
<div class="comment-text">
<h4>{{ each.content }}</h4>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-3">
</div>

The loading problem you see is that the data is fetched after the view has been created. You can delay the loading of the view by using the resolve property of the route:
.when('/allStories', {
templateUrl : 'app/views/pages/allStories.html',
controller: 'AllStoryController',
controllerAs: 'story',
resolve: {
stories: function(Story) {
return Story.allStories();
}
}
})
Angular will delay the loading of the view until all resolve properties have been resolved. You then inject the property into the controller:
.controller('AllStoryController', function(socketio, stories) {
var vm = this;
vm.stories = stories.data;
});

I think you should use local storage. suited module - angular-local-storage
The data is kept aslong you or the client user clean the data,
Usage is easily:
bower install angular-local-storage --save
var storyService = angular.module('storyService', ['LocalStorageModule']);
In a controller:
storyService.controller('myCtrl', ['$scope', 'localStorageService',
function($scope, localStorageService) {
localStorageService.set(key, val); //return boolean
localStorageService.get(key); // returl val
}]);
Match this usage to your scenario (for example - put the stories array on and just append updates to it)

Related

#ModelAttribute in my REST comes empty

I am trying to pass data through <select multiple> from HTML to my RESTful.
That data is an array of String. I don't know why when it comes to my backend it's empty.
This is my REST:
#PutMapping("/events")
#Timed
public ResponseEntity<Event> updateEvent(#RequestBody Event event, #ModelAttribute("attendeesToParse") ArrayList<String> attendeesToParse) throws URISyntaxException {
//Some code
}
This is my HTML:
<div class="form-group">
<label>Attendees</label>
<select class="form-control" multiple name="attendeesToParse" ng-model="vm.usernames"
ng-options="customUser as customUser.username for customUser in vm.customusers">
<option value=""></option>
</select>
</div>
I tried to fix this one for days, I googled it so much but I found no solutions. Please help me.
I can not change my HTML into a JSP due to my project's structure and business logic.
Why does it come empty? If I try to show some logs I see an empty array [].
UPDATE
My HTML form call:
<form name="editForm" role="form" novalidate ng-submit="vm.save()">
<!-- some code -->
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" ng-click="vm.clear()">
<span class="glyphicon glyphicon-ban-circle"></span> <span data-translate="entity.action.cancel">Cancel</span>
</button>
<button type="submit" ng-disabled="editForm.$invalid || vm.isSaving" class="btn btn-primary">
<span class="glyphicon glyphicon-save"></span> <span data-translate="entity.action.save">Save</span>
</button>
</div>
</form>
My event-dialog-controller.js: (is the .js controller that works with form)
(function() {
'use strict';
angular
.module('businessRequestApp')
.controller('EventDialogController', EventDialogController);
EventDialogController.$inject = ['$timeout', '$scope', '$stateParams', '$uibModalInstance', '$q', 'entity', 'Event', 'Desk', 'CustomUser'];
function EventDialogController ($timeout, $scope, $stateParams, $uibModalInstance, $q, entity, Event, Desk, CustomUser) {
var vm = this;
vm.event = entity;
vm.clear = clear;
vm.datePickerOpenStatus = {};
vm.openCalendar = openCalendar;
vm.save = save;
vm.reftables = Desk.query({filter: 'event-is-null'});
$q.all([vm.event.$promise, vm.reftables.$promise]).then(function() {
if (!vm.event.refTable || !vm.event.refTable.id) {
return $q.reject();
}
return Desk.get({id : vm.event.refTable.id}).$promise;
}).then(function(refTable) {
vm.reftables.push(refTable);
});
vm.customusers = CustomUser.query();
$timeout(function (){
angular.element('.form-group:eq(1)>input').focus();
});
function clear () {
$uibModalInstance.dismiss('cancel');
}
function save () {
vm.isSaving = true;
if (vm.event.id !== null) {
Event.update(vm.event, onSaveSuccess, onSaveError);
} else {
Event.save(vm.event, onSaveSuccess, onSaveError);
}
}
function onSaveSuccess (result) {
$scope.$emit('businessRequestApp:eventUpdate', result);
$uibModalInstance.close(result);
vm.isSaving = false;
}
function onSaveError () {
vm.isSaving = false;
}
vm.datePickerOpenStatus.date = false;
function openCalendar (date) {
vm.datePickerOpenStatus[date] = true;
}
}
})();
My event-service.js:
(function() {
'use strict';
angular
.module('businessRequestApp')
.factory('Event', Event);
Event.$inject = ['$resource', 'DateUtils'];
function Event ($resource, DateUtils) {
var resourceUrl = 'api/events/:id';
return $resource(resourceUrl, {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
if (data) {
data = angular.fromJson(data);
data.date = DateUtils.convertLocalDateFromServer(data.date);
}
return data;
}
},
'update': {
method: 'PUT',
transformRequest: function (data) {
var copy = angular.copy(data);
copy.date = DateUtils.convertLocalDateToServer(copy.date);
return angular.toJson(copy);
}
},
'save': {
method: 'POST',
transformRequest: function (data) {
var copy = angular.copy(data);
copy.date = DateUtils.convertLocalDateToServer(copy.date);
return angular.toJson(copy);
}
}
});
}
})();
My event.controller.js:
(function () {
'use strict';
angular
.module('businessRequestApp')
.controller('EventController', EventController);
EventController.$inject = ['Event', 'CustomUser', '$scope'];
function EventController(Event, CustomUser, $scope) {
var vm = this;
vm.events = [];
vm.customUsers = [];
vm.usernames = ["test1", "test2", "test3"];
$scope.allCustomUsers = [];
loadAll();
function loadAll() {
Event.query(function (result) {
vm.events = result;
vm.searchQuery = null;
});
CustomUser.query(function (result) {
vm.customUsers = result;
vm.searchQuery = null;
for (var i = 0; i < vm.customUsers.length; i++) {
$scope.allCustomUsers.push(vm.customUsers[i].username);
}
});
}
}
})();
If you're using angularJS, you can't data bind data with #ModelAttribute, because #ModelAttribute exists only with template engines such as JSP, and AngularJS is not a template engine within Spring. Try instead to use #RequestBody on String parameter, and then extract the data using Jackson.
One more issue, How exactly do you pass your values from front to back? I don't see any $http angularJS call, and no HTML form with POST method.

Angular $scope is not available in the HTML Template but I can see it in console log?

I have been following some online tutorials and using the angularjs-template to get started with Angular. I can't get the page (html template) to update with the controller. I think there is a problem with the way I have set up the controller as the values are not available to the html template.
I have been trying to follow some of the best practive guides which suggested to wrap my components in an 'Invoked Function Expression' and to seperate out the controller, service and service manager. However, I think I have made a bit of a hash of this and need some help to figure out what I am doing wrong.
With the console I can see that $scope.metric contains the information I want. For me this means that the controller has successfully pulled the data back from my API via the metricService. However I can't seem to have the results printed back onto the html page e.g. metric.id.
Any help appreciated - I am at the end of my wits trying to figure this out.
metric.html
<div class="panel panel-primary">
<div class="panel-body">
<!-- Try First Way to Print Results -->
Id: <span ng-bind="metric.id"></span></br>
Name:<input type="text" ng-model="metric.metadata.name" /></br>
<!-- Try Second Way to Print Results -->
<p data-ng-repeat="thing in ::MEC.metric track by $index">
{{$index + 1}}. <span>{{thing.metadata.name}}</span>
<span class="glyphicon glyphicon-info-sign"></span>
</a>
</p>
<!-- Try Third Way to Print Results -->
Id: <span ng-bind="Metric.metricId"></span></br>
Id: <span ng-bind="Metric.id"></span></br>
Id: <span ng-bind="metricService.id"></span></br>
<!-- Try Fourth Way to Print Results -->
Id: <strong>{{::MEC.metric.id}}</strong></br>
Name: <strong>{{::MEC.metric.metadata.name}}</strong></br>
Height: <strong>{{::MEC.metric.type}}</strong>
</div>
metricController.js
(function () {
'use strict';
angular.module('app.metric', ['app.metricService', 'app.metricManager'])
.controller('MetricController', MetricController)
MetricController.$inject = ['$scope', 'metricManager', '$log'];
function MetricController($scope, metricManager, $log) {
metricManager.getMetric(0).then(function(metric) {
$scope.metric = metric
$log.info('$scope.metric printed to console below:');
$log.info($scope.metric);
})
}
})();
metricService.js
(function () {
'use strict';
angular.module('app.metricService', [])
.factory('Metric', ['$http', '$log', function($http, $log) {
function Metric(metricData) {
if (metricData) {
this.setData(metricData);
}
// Some other initializations related to book
};
Metric.prototype = {
setData: function(metricData) {
angular.extend(this, metricData);
},
delete: function() {
$http.delete('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId);
},
update: function() {
$http.put('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId, this);
},
hasMetadata: function() {
if (!this.metric.metadata || this.metric.metadata.length === 0) {
return false;
}
return this.metric.metadata.some(function(metadata) {
return true
});
}
};
return Metric;
}]);
})();
metricManager.js
(function () {
'use strict';
angular.module('app.metricManager', [])
.factory('metricManager', ['$http', '$q', 'Metric', function($http, $q, Metric) {
var metricManager = {
_pool: {},
_retrieveInstance: function(metricId, metricData) {
var instance = this._pool[metricId];
if (instance) {
instance.setData(metricData);
} else {
instance = new Metric(metricData);
this._pool[metricId] = instance;
}
return instance;
},
_search: function(metricId) {
return this._pool[metricId];
},
_load: function(metricId, deferred) {
var scope = this;
$http.get('https://n4nite-api-n4nite.c9users.io/v1/imm/metrics/' + metricId).then(successCallback, errorCallback)
function successCallback(metricData){
//success code
var metric = scope._retrieveInstance(metricData.id, metricData);
deferred.resolve(metric);
};
function errorCallback(error){
//error code
deferred.reject();
}
},
/* Public Methods */
/* Use this function in order to get a metric instance by it's id */
getMetric: function(metricId) {
var deferred = $q.defer();
var metric = this._search(metricId);
if (metric) {
deferred.resolve(metric);
} else {
this._load(metricId, deferred);
}
return deferred.promise;
},
/* Use this function in order to get instances of all the metrics */
loadAllMetrics: function() {
var deferred = $q.defer();
var scope = this;
$http.get('ourserver/books')
.success(function(metricsArray) {
var metrics = [];
metricsArray.forEach(function(metricData) {
var metric = scope._retrieveInstance(metricData.id, metricData);
metrics.push(metric);
});
deferred.resolve(metrics);
})
.error(function() {
deferred.reject();
});
return deferred.promise;
},
/* This function is useful when we got somehow the metric data and we wish to store it or update the pool and get a metric instance in return */
setMetric: function(metricData) {
var scope = this;
var metric = this._search(metricData.id);
if (metric) {
metric.setData(metricData);
} else {
metric = scope._retrieveInstance(metricData);
}
return metric;
},
};
return metricManager;
}]);
})();
Snippet from App.routes
.state('root.metric', {
url: 'metric',
data: {
title: 'Metric',
breadcrumb: 'Metric'
},
views: {
'content#': {
templateUrl: 'core/features/metric/metric.html',
controller: 'MetricController',
controllerAs: 'MEC'
}
}
})
Console
You are mixing two concepts controller alias and $scope, in your case you are creating controller alias as MEC using controllerAs. If you are using controller alias then this will work fine for you :
function MetricController($scope, metricManager, $log) {
var MEC = this;
metricManager.getMetric(0).then(function(metric) {
MEC.metric = metric
$log.info('$scope.metric printed to console below:');
$log.info($scope.metric);
})
}
If you don't want to use controller alias and share data between view and controller via $scope then in your view you should use something like this {{::metric.metadata.name}} and controller function should stay as it is.
PS: If you are using alias then MEC in var MEC = this can be MEC or abc or any name you like but convention is to use var vm = this and controllerAs: 'vm'. If you have controllerAs: 'xyz' then in your view xyz should be used to access model.
Problem with your view HTML, you need to use proper Angular expressions while binding. When you want use ::MEC alias name you need to mark your controller with as keyowrd, like ng-controller="xyz as MEC". And checkout working Plunker
<div class="panel panel-primary">
<div class="panel-body">
<!-- Try First Way to Print Results -->
Id: <span ng-bind="metric.id"></span>
<br> Name1:
<input type="text" ng-model="metric.metadata.name" />
<br><br><br><br>
<!-- Try Second Way to Print Results -->
<p data-ng-repeat="thing in [metric] track by $index">
{{$index + 1}}. <span>{{thing.metadata.name}}</span>
<span class="glyphicon glyphicon-info-sign"></span>
</p><br><br><br>
<!-- Try Third Way to Print Results -->
Id: <span ng-bind="metric.metricId"></span>
<br> Id: <span ng-bind="metric.id"></span>
<br><br><br>
<!-- Try Fourth Way to Print Results -->
Id: <strong>{{::metric.id}}</strong>
<br> Name: <strong>{{::metric.metadata.name}}</strong>
<br> Height: <strong>{{::metric.type}}</strong>
</div>
</div>

Getting undefined in AngularJS

I'm working on building a little app that accepts input from a form (the input being a name) and then goes on to POST the name to a mock webservice using $httpBackend. After the POST I then do a GET also from a mock webservice using $httpBackend that then gets the name/variable that was set with the POST. After getting it from the service a simple greeting is constructed and displayed back at the client.
However, currently when the data gets displayed now back to the client it reads "Hello undefined!" When it should be reading "Hello [whatever name you inputed] !". I used Yeoman to do my app scaffolding so I hope everyone will be able to understand my file and directory structure.
My app.js:
'use strict';
angular
.module('sayHiApp', [
'ngCookies',
'ngMockE2E',
'ngResource',
'ngSanitize',
'ngRoute'
])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
})
.run(function($httpBackend) {
var name = 'Default Name';
$httpBackend.whenPOST('/name').respond(function(method, url, data) {
//name = angular.fromJson(data);
name = data;
return [200, name, {}];
});
$httpBackend.whenGET('/name').respond(name);
// Tell httpBackend to ignore GET requests to our templates
$httpBackend.whenGET(/\.html$/).passThrough();
});
My main.js:
'use strict';
angular.module('sayHiApp')
.controller('MainCtrl', function ($scope, $http) {
// Accepts form input
$scope.submit = function() {
// POSTS data to webservice
setName($scope.input);
// GET data from webservice
var name = getName();
// Construct greeting
$scope.greeting = 'Hello ' + name + ' !';
};
function setName (dataToPost) {
$http.post('/name', dataToPost).
success(function(data) {
$scope.error = false;
return data;
}).
error(function(data) {
$scope.error = true;
return data;
});
}
// GET name from webservice
function getName () {
$http.get('/name').
success(function(data) {
$scope.error = false;
return data;
}).
error(function(data) {
$scope.error = true;
return data;
});
}
});
My main.html:
<div class="row text-center">
<div class="col-xs-12 col-md-6 col-md-offset-3">
<img src="../images/SayHi.png" class="logo" />
</div>
</div>
<div class="row text-center">
<div class="col-xs-10 col-xs-offset-1 col-md-4 col-md-offset-4">
<form role="form" name="greeting-form" ng-Submit="submit()">
<input type="text" class="form-control input-field" name="name-field" placeholder="Your Name" ng-model="input">
<button type="submit" class="btn btn-default button">Greet Me!</button>
</form>
</div>
</div>
<div class="row text-center">
<div class="col-xs-12 col-md-6 col-md-offset-3">
<p class="greeting">{{greeting}}</p>
</div>
</div>
At the moment your getName() method returns nothing. Also you cant just call getName() and expect the result to be available immediately after the function call since $http.get() runs asynchronously.
You should try something like this:
function getName () {
//return the Promise
return $http.get('/name').success(function(data) {
$scope.error = false;
return data;
}).error(function(data) {
$scope.error = true;
return data;
});
}
$scope.submit = function() {
setName($scope.input);
//wait for the Promise to be resolved and then update the view
getName().then(function(name) {
$scope.greeting = 'Hello ' + name + ' !';
});
};
By the way you should put getName(), setName() into a service.
You can't return a regular variable from an async call because by the time this success block is excuted the function already finished it's iteration.
You need to return a promise object (as a guide line, and preffered do it from a service).
I won't fix your code but I'll share the necessary tool with you - Promises.
Following angular's doc for $q and $http you can build yourself a template for async calls handling.
The template should be something like that:
angular.module('mymodule').factory('MyAsyncService', function($q, http) {
var service = {
getNames: function() {
var params ={};
var deferObject = $q.defer();
params.nameId = 1;
$http.get('/names', params).success(function(data) {
deferObject.resolve(data)
}).error(function(error) {
deferObject.reject(error)
});
return $q.promise;
}
}
});
angular.module('mymodule').controller('MyGettingNameCtrl', ['$scope', 'MyAsyncService', function ($scope, MyAsyncService) {
$scope.getName = function() {
MyAsyncService.getName().then(function(data) {
//do something with name
}, function(error) {
//Error
})
}
}]);

JSON request with Angular Displays an Empty Response

I believe Angular is loading the page before it receives all the information from JSONP. If I refresh the page a couple of times I do get the information to display; however, it is not constant. My code is almost the same as the code I am using on my projects page which does not have the same issue.
HTML:
<div class="container">
<div class="row push-top" ng-show="user">
<div class="col-xs-10 col-xs-offset-1 col-sm-10 col-sm-offset-1 col-md-10 col-md-offset-1">
<div class="well well-sm">
<div class="row">
<div class="col-sm-3 col-md-2">
<img ng-src="[[ user.images.138 ]]" alt="" class="img-rounded img-responsive" />
</div>
<div class="col-sm-7 col-md-8">
<h4 ng-bind="user.display_name"></h4>
<h5 ng-bind="user.occupation"></h5>
<i class="fa fa-map-marker"></i>
<cite title="[[ user.city ]], [[ user.country ]]">[[ user.city ]], [[ user.country ]]</cite>
<br>
<strong ng-bind="user.stats.followers"></strong> Followers, <strong ng-bind="user.stats.following"></strong> Following
<hr>
<p style="margin-top:10px;" ng-bind="user.sections['About Me']"></p>
</div>
</div>
</div>
</div>
</div>
</div>
JavaScipt:
'use strict';
angular.module('angularApp')
.controller('AboutCtrl', function ($scope, $window, Behance) {
$scope.loading = true;
Behance.getUser('zachjanice').then(function (user) {
$scope.user = user;
$scope.loading = false;
}, function (error) {
console.log(error);
$scope.loading = false;
$scope.user = null;
});
$scope.gotoUrl = function (url) {
$window.location.href = url;
};
});
You can see the page in question at: http://zachjanice.com/index.html#/about. Thanks in Advance.
As requested here is the behance service:
'use strict';
angular.module('angularApp')
.factory('Behance', function ($http, $q, localStorageService, BEHANCE_CLIENT_ID) {
// Should be called to refresh data (for testing purposes)
// localStorageService.clearAll();
// Public API
return {
// Get a list of projects
getProjects: function (config) {
var pageNum = 1;
if (angular.isObject(config) && angular.isDefined(config.page)) {
pageNum = config.page;
}
var _projects = $q.defer(),
_storedProjects = localStorageService.get('Projects_Page_');
if (_storedProjects !== null) {
_projects.resolve(_storedProjects);
} else {
$http.jsonp('https://www.behance.net/v2/users/zachjanice/projects', {
params: {
'client_id': BEHANCE_CLIENT_ID,
'callback': 'JSON_CALLBACK',
'page': pageNum
}
})
.then(function (response) {
if (response.data.http_code === 200 && response.data.projects.length > 0) {
// console.log('getting page', _page);
_projects.resolve(response.data.projects);
localStorageService.add('Projects_Page_' + pageNum, response.data.projects);
}
});
}
return _projects.promise;
},
// Get project with id
getProject: function (id) {
var _project = $q.defer();
$http.jsonp('https://www.behance.net/v2/projects/' + id, {
params: {
'client_id': BEHANCE_CLIENT_ID,
'callback': 'JSON_CALLBACK'
},
cache: true
}).success(function (data){
_project.resolve(data.project);
});
return _project.promise;
},
// Get project with id
getUser: function (username) {
var _user = $q.defer();
$http.jsonp('https://www.behance.net/v2/users/' + username, {
params: {
'client_id': BEHANCE_CLIENT_ID,
'callback': 'JSON_CALLBACK'
},
cache: true
}).success(function (data){
_user.resolve(data.user);
});
return _user.promise;
}
};
});
Anthony Chu supplied no support, so I found the answer myself. The issue was not the Behance Service, but the Projects Controller like I had originally stated.
I changed $scope.loading under the call for the service from false to true. Works every time.

Expected response to contain an object but got an array

I get this error, I found many thread with the same message, but it never seems to match my case, and I didn't manager to solve it.
Basivally, everything was ok until I tried to make 1 form for create and update a 'Car' object.
Here is a presentation of my app (build from this template: https://github.com/linnovate/mean):
/public/js/config.js:
[...]
.state('edit car', {
url: '/cars/:carId/edit',
templateUrl: 'views/cars/edit.html'
})
.state('create car', {
url: '/cars/create',
templateUrl: 'views/cars/edit.html'
})
/public/js/services/mycars.js (don't really know what services are used for...):
//Cars service used for car REST endpoint
angular.module('mean.mycars').factory('Cars', ['$resource', function($resource) {
return $resource('cars/:carId', {
carId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}]);
public/js/controllers/mycars.js:
angular.module('mean.mycars').controller('MyCarsController', ['$scope', '$http', '$stateParams', '$location', 'Global', 'Cars',
function ($scope, $http, $stateParams, $location, Global, Cars) {
$scope.findOneOrCreate = function () {
// create a new car
var car = new Cars({
id : null,
marque: this.marque,
modele: this.modele,
desc: this.desc
});
// put new car in scope
$scope.car = car;
// if there is a param, search for the car (mode update)
if ($stateParams.carId !== null){
Cars.get({
carId: $stateParams.carId
}, function(carTmp) {
// put the result in scope
$scope.car = carTmp;
});
}
};
$scope.createOrUpdate = function () {
var car = $scope.car;
if (car.id !== null) {
// update
if (!car.updated) {
car.updated = [];
}
car.updated.push(new Date().getTime());
car.$update(function () {
$location.path('cars/' + car._id);
});
}
else {
//Create
car.$save(function (response) {
$location.path('cars/' + response._id);
});
}
};
And finally my view: edit.html:
<section data-ng-controller="MyCarsController" data-ng-init="findOneOrCreate()">
<form class="form-horizontal col-md-6" role="form" data-ng-submit="createOrUpdate()">
<div class="form-group">
<label for="title" class="col-md-2 control-label">Title</label>
<div class="col-md-10">
<input type="text" class="form-control" data-ng-model="car.modele" id="title" placeholder="Title" required>
</div>
</div>
<div class="form-group">
<label for="content" class="col-md-2 control-label">Content</label>
<div class="col-md-10">
<textarea data-ng-model="car.marque" id="content" cols="30" rows="10" placeholder="Content" class="form-control" required></textarea>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</div>
</form>
</section>
Edit to add infos:
The web Services are supposed to return only one car (but not sure if they do), here they are:
exports.car = function(req, res, next, id) {
Car.load(id, function(err, car) {
if (err) return next(err);
if (!car) return next(new Error('Failed to load car ' + id));
req.car = car;
next();
});
};
exports.create = function(req, res) {
var car = new Car(req.body);
car.user = req.user;
car.save(function(err) {
if (err) {
return res.send('users/signup', {
errors: err.errors,
car: car
});
} else {
res.jsonp(car);
}
});
};
exports.update = function(req, res) {
var car = req.car;
car = _.extend(car, req.body);
car.save(function(err) {
if (err) {
return res.send('users/signup', {
errors: err.errors,
car: car
});
} else {
res.jsonp(car);
}
});
};
Error message appears when I go to /cars/create, not when I go to /cars/:carsId/edit:
Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an object but got an array
http://errors.angularjs.org/1.2.15/$resource/badcfg?p0=object&p1=array
Is your web service returning an array? The get method expects only one object to be returned, and the same with your PUT request if you're returning something. If you're expecting multiple you will need to specify isArray: true in your service method in mycars.js. See example here: http://docs.angularjs.org/api/ngResource/service/$resource

Categories

Resources