angular promise - on submit gets "Error: args is null $parseFunctionCall" - javascript

I am currently following this tuto on MEAN.js : https://thinkster.io/mean-stack-tutorial/ .
I am stuck into the end of "Wiring Everything Up", I am completlty new to angular so I am not pretending I understood everything I did. Here is the situation :
We are using the plugin ui-router.
First here is the html template :
<form name="addComment" ng-submit="addComment.$valid && addComment()"novalidate>
<div class="form-group">
<input class="form-control" type="text" placeholder="Comment" ng-model="body" required/>
</div>
<button type="submit" class="btn btn-primary">Comment</button>
</form>
The error "Error: args is null $parseFunctionCall" occurs only when I submit the form
Then, here is the configuration step for this page :
app.config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('posts', {
url : '/posts/{id}',
templateUrl: '/posts.html',
controller : 'PostsCtrl',
resolve : {
post: ['$stateParams', 'posts', function ($stateParams, posts) {
return posts.get($stateParams.id);
}]
}
});
$urlRouterProvider.otherwise('home');
}]);
There, is the controller :
app.controller('PostsCtrl', ['$scope', 'posts', 'post',
function ($scope, posts, post) {
$scope.post = post;
$scope.addComment = function () {
posts.addComment(post._id, {
body : $scope.body,
author: 'user'
}).success(function (comment) {
$scope.post.comments.push(comment);
});
$scope.body = '';
};
$scope.incrementUpVote = function (comment) {
posts.upvoteComment(post, comment);
};
}]);
And Finally, the factory where the posts are retrieved from a remote webservice
app.factory('posts', ['$http', function ($http) {
var o = {
posts: []
};
o.get = function (id) {
return $http.get('/posts/' + id).then(function (res) {
return res.data;
});
};
o.addComment = function (id, comment) {
return $http.post('/posts/' + id + '/comments', comment);
};
return o;
}]);
I've only given the parts that I think are relevant.
I suspect that the problem is comming from the promise and the scope which have been unlinked. I searched about promises but I think that ui-router is doing it differently.
I tried some $watch in the controller but without succeding.
Has anyone some idea about that ? Thank you in advance

The form name addComment (used for addComment.$valid) and the function addComment added to the scope are clashing with each other, rename one or the other.
See the Angular docs for the form directive:
If the name attribute is specified, the form controller is published
onto the current scope under this name.
As you are manually also adding a function named addComment, it is using the wrong one when evaluating the ng-submit.

Related

AngularJS app loading and processing JSON data once for multiple controllers

I'm working on an Angular app, where I'm running into mostly the same problem as in this post:
AngularJS App: Load data from JSON once and use it in several controllers
I've got a factory that reads a JSON file, and returns the whole data object. Each controller, then, uses this factory (as a service?) to obtain the data, but then each controller has to pick it apart on its own. The JSON has to be searched and processed to get the relevant payload like, $scope.currentArray = data.someThing.allItems[i]; etc, and I obviously don't want to repeat this code in all the controllers.
Seems to me I can either find some way to share the data, after, say, MainController (the "first one") has finished working it, or I can add some new module "between" the controllers and the factory. This new module -- let's call it myProcessService? -- would then be the one getting the data object from the factory, and do all the processing there... once and for all. Then, each controller would only deal with myProcessService to (somehow) get the ready-formatted variables and arrays etc onto their respective scopes (yes, this is Angular 1).
If I try to give an example of how I'm doing this so far, maybe someone can help me with the necessary improvements? And, I am aware that it is a good idea to begin using the Angular 2 patterns already today, but please understand that I am first trying to get some grasp of how A1 works, before delving into A2 :)
var app = angular.module('myApp', ['ngRoute']);
app.factory('getDataFile', ['$http', function($http) {
function getStream(pid) {
return $http.get("data/" + pid + ".json")
.success(function(data) {
console.info("Found data for pid " + pid);
return data;
})
.error(function(err) {
console.error("Cant find data for pid " + pid);
return err;
});
}
return {getStream: getStream};
}]);
app.controller('MainController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
getDataFile.getStream('10101011').success(function(data) {
// process "data" into what's relevant:
var i = getRelevantIndexForToday(new Date());
$scope.myVar = data.someField;
$scope.currentArray = data.someThing.allItems[i];
// etc... you get the drift
}
}]);
app.controller('SecondController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
getDataFile.getStream('10101011').success(function(data) {
// process "data" into what's relevant:
var i = getRelevantIndexForToday(new Date());
$scope.myVar = data.someField;
$scope.currentArray = data.someThing.allItems[i];
// etc... you get the drift
}
}]);
Edit:
My ngRouter is set up something like this. They fill the ng-view div in my index.html. However -- and maybe this is frowned upon? -- I've also got a "MainController" which sits directly in the index.html body tag, such that I can show some data (from the back end) in the header part of the single page application.
app.config(function($routeProvider) {
$routeProvider
.when('/:id/work/:page_id', {
controller: 'AssetController',
templateUrl: 'app/views/work.html'
})
.when('/:id/work/', {
redirectTo: '/:id/work/1'
})
.when('/:id/', {
controller: 'DashController',
templateUrl: 'app/views/dashboard.html'
})
.otherwise({
redirectTo: '/'
});
});
and index.html is a lot like this:
<body ng-app="myApp">
<div class="container" ng-controller="MainController">
<h1>Welcome, {{username}}</h1>
<div ng-view></div>
</div>
</body>
You can add another helper function in your factory, that returns the required object that you want to share between controllers.
app.factory('getDataFile', ['$http', function($http) {
function getStream(pid) {
return $http.get("data/" + pid + ".json")
.success(function(data) {
console.info("Found data for pid " + pid);
return data;
})
.error(function(err) {
console.error("Cant find data for pid " + pid);
return err;
});
}
function getCurrent(pid) {
return getStream(pid).then(function() {
var i = getRelevantIndexForToday(new Date());
return {
myVar: data.someField,
currentArray: data.someThing.allItems[i];
};
});
}
return {
getStream: getStream,
getCurrent: getCurrent
};
}]);
app.controller('MainController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
getDataFile.getCurrent('10101011').success(function(data) {
$scope.myVar = data.myVar;
$scope.currentArray = data.currentArray;
// etc... you get the drift
}
}]);
app.controller('SecondController', ['$scope', 'current',
function($scope, current) {
.success(function(data) {
$scope.myVar = data.myVar;
$scope.currentArray = data.currentArray;
}
}]);
Suggestion:
Also I suggest you to use resolve which allows you to pass data to your controller from your route.
Route:
.when('/:id/work', {
controller: 'AssetController',
templateUrl: 'app/views/work.html',
resolve: {
// you are injecting current variable in the controller with the data. You can inject this to each of your controller. you dont need to add the whole function in your next route. Just use current
current: function(getDataFile){
return getDataFile.getCurrent('10101011');
}
})
Controller:
app.controller('MainController', ['$scope', 'current',
function($scope, current) {
$scope.myVar = current.myVar;
$scope.currentArray = current.currentArray;
}]);
app.controller('SecondController', ['$scope', 'current',
function($scope, current) {
$scope.myVar = current.myVar;
$scope.currentArray = current.currentArray;
}]);
Now that you have
Thanks for giving an answer in line with my use of deprecated methods success and error, Subash. However, I had some problems with the code in your answer, and I got some help on #angularjs, so I thought I should post the updated code here.
var myApp = angular.module('myApp',[]);
myApp.factory('getDataFile', ['$http', function($http) {
function getStream(pid) {
// here, using placeholder data URL, just to get some data:
return $http.get('http://jsonplaceholder.typicode.com/users')
.then(function(result) {
console.info("Found data for pid " + pid);
return result.data;
})
.catch(function(err) {
console.error("Cant find data for pid " + pid);
return err;
});
}
function getCurrent(pid) {
return getStream(pid).then(function(data) {
var i = 1; // test
console.log("myVar = ", data[i].name);
return {
myVar: data[i].name
};
});
}
return {
getStream: getStream,
getCurrent: getCurrent
};
}]);
myApp.controller('MainController', ['$scope', 'getDataFile',
function($scope, getDataFile) {
$scope.name = "j";
getDataFile.getCurrent('10101011').then(function(user) {
$scope.myVar = user.myVar;
console.log("controller. myVar = ", user);
// etc... you get the drift
});
}]);

AngularFire - How to define item ID for child template with ng-repeat?

Maybe my issue seems easy to resolve, but I've this problem since a lot of hours : When I'm in my dashboard, all data of my Firebase database are visible (With Ng-repeat).
But I can't found a solution for choose one specific item and see his details in another page.
I've test this method in HTML (This is an example) :
<div ng-repeat="post in posts">
<div class="card" ng-href="#/post/">">
<h1>{{post.title}}</h1>
<p>{{post.content}}</p>
</div>
</div>
In App JS :
.state('tabpost', {
url: 'tabpost/id',
templateUrl: 'templates/tab-post.html',
controller: 'PostCtrl'
})
In Service JS (in Post Factory) :
myApp.factory("Post", ["$firebaseArray", "$firebaseObject", function($firebaseArray, $firebaseObject) {
var postRef = new Firebase('https://myApp.firebaseio.com/Posts/');
var userRef = new Firebase('https://myApp.firebaseio.com/Users/');
var posts = $firebaseArray(postRef);
var Post = {
all: posts,
get: function (postKey){
var postId = $firebaseObject(postRef);
return $firebaseObject(eventRef.child('Posts').child(postId).child(userid));
}
,
add: function (post){
var postId = $firebaseArray(postRef, userRef);
event.userid = userRef.getAuth();
return postId.$add(post);
}
}
return Post;
}]);
My PostCtrl :
myApp.controller('PostCtrl', ['$ionicFrostedDelegate', '$ionicScrollDelegate','$state','$scope', 'Post', 'Auth', '$firebaseObject', '$firebaseArray', function($ionicFrostedDelegate, $ionicScrollDelegate, $state,$scope, Post, Auth, $firebaseObject, $firebaseArray) {
var PostRef = new Firebase("https://myApp.firebaseio.com/Posts");
$scope.posts = Post.all;
$scope.post = {'title': '', 'content': ''};
$scope.auth = Auth;
PS : It took 16 hours to try a bunch of tutorials mostly obsolete , and I am sure that the solution can not be that simple.
I already posted two similar issues yesterday and this morning but each of the proposed solutions have not worked . I would be immensely grateful to the person who would help me out of this impasse .
I still have a little trouble with jsFiddle promised I would learn to use it once I would have solved this problem.
Thank you for giving me time
Can you please try the following set of codes, I've explained the changes in comments in Controller and added :id in App JS
In App JS :
.state('tabpost', {
url: 'tabpost/:id',
templateUrl: 'templates/tab-post.html',
controller: 'PostCtrl'
})
PostCtrl :
myApp.controller('PostCtrl', ['$ionicFrostedDelegate', '$ionicScrollDelegate','$state','$scope', 'Post', 'Auth', '$firebaseObject', '$firebaseArray', '$routeParams', function($ionicFrostedDelegate, $ionicScrollDelegate, $state,$scope, Post, Auth, $firebaseObject, $firebaseArray, $routeParams) {
var PostRef = new Firebase("https://myApp.firebaseio.com/Posts");
var id = $routeParams.id; //get the id from url, $routeParams is injected in controller
$scope.posts = Post.get(id); //call get() method of Post with the id retrieved
$scope.post = {'title': '', 'content': ''};
$scope.auth = Auth;
you can use route provider to do that. I used that for my application and it works great.
myApp.config( ['$routeProvider', function($routeProvider){
$routeProvider.
when('tabpost', {
templateUrl: 'tabpost/id',
controller: 'PostCtrl'
});
}]);

Redirect to another view by a post id, not working

I am receiving an external object from WordPress, in one view I have the post.title, and if you click in that title you can go to another view and see te entire post.content.
So far, I can not see the entire post because I am getting a couple errors, posts is undefined.
I made a Plunkr, CodePen and one JSBin for you to understand easier. If you use JSBin is better because you can use the console which is integrated there. All you have to do is click on the title of the post, and you are going to realize that can not go to the other view.
Here is the code regarding my issue, which is the same you will see in the online editors I post above
.state('tabs', {
url: "/tabs",
abstract: true,
templateUrl: "tabs.html"
})
.state('tabs.news', {
url: "/news",
views: {
'tab-news': {
templateUrl: "tab-news.html",
controller: 'NewsCtrl'
}
}
})
.state('tabs.post-detail', {
url: '/news/:postId',
views: {
'tab-news': {
templateUrl: 'tab-post-detail.html',
controller: 'PostDetailCtrl'
}
}
})
the html for the main view, news
<a ng-href="#/tabs/news/{{post.ID}}">
<h2 ng-bind-html="post.title"></h2>
<p>{{post.date | date}}</p>
</a>
and here is the view where you can not enter yet, the view where are redirected after clicking in the title on the main view
<div>
<h3>{{:: post.title}}</h3>
<p>{{:: post.content}}</p>
</div>
now the controller for the main view
.controller('NewsCtrl', function($scope, $ionicLoading, FreshlyPressed) {
$scope.posts = [];
$scope.doRefresh = function() {
$scope.posts = FreshlyPressed.getBlogs($scope);
}
});
here the service
angular.module('urbanet.app.service', [])
.service('FreshlyPressed', function($http) {
return {
getBlogs: function($scope) {
$scope.posts = [];
$http.jsonp('https://public-api.wordpress.com/rest/v1.1/freshly-pressed?callback=JSON_CALLBACK')
.success(function(result) {
$scope.posts = result.posts;
});
},
get: function(postId, $scope) {
console.log(postId);
console.log($scope.posts);
for (var i = 0; i < $scope.posts.length; i++) {
if ($scope.posts[i].id === parseInt(postId)) {
return $scope.posts[i];
}
}
return null;
}
}
})
and controller for the second view, the view of the entire post
.controller('PostDetailCtrl', function($scope, $stateParams, FreshlyPressed) {
$scope.post = FreshlyPressed.get($stateParams.postId, $scope);
});
You are going to have to make a new request for individual posts
The freshly-pressed api returns to you a siteID and postId.
You then combine those to use the posts API to get the single post.
Since freshly-pressed is a constantly changing list, this is the only way you would ever be able to bookmark posts. Tomorrow you may not get the same set of main posts, so wouldn't be able to replicate links that were used today the way you are attempting to
Service method:
getPostById: function(siteId,postId ) {
var url ='https://public-api.wordpress.com/rest/v1.1/sites/'+siteId+'/posts/'+postId+'?callback=JSON_CALLBACK'
return $http.jsonp(url)
}
controller
.controller('PostDetailCtrl', function($scope, $stateParams, FreshlyPressed) {
var postId = $stateParams.postId,
siteId = $stateParams.siteId;
FreshlyPressed.getPostById(siteId,postId).success(function(response){
$scope.post = response
})
});
Modify links accordingly
<a ng-href="#/tabs/news/{{post.site_ID}}/{{post.ID}}">
Working demo
.controller('PostDetailCtrl', function($scope, $stateParams, FreshlyPressed) {
$scope.post = FreshlyPressed.get($stateParams.postId, $scope);
});
This is a problem. You are trying to pass the entire $scope object as a parameter?
What exactly do you want to pass to the get call?
You have this:
get: function(postId, $scope) { //<- that shouldn't be $scope, make it 'post' or something
console.log(postId);
console.log($scope.posts); //Notice that this comes back undefined?
for (var i = 0; i < $scope.posts.length; i++) { //<- length throws an error because there isn't anything there.
if ($scope.posts[i].id === parseInt(postId)) {
return $scope.posts[i];
}
}
return null;
}
You shouldn't be trying to pass $scope as a param to your service then access $scope inside the factory.
Have your service store your posts data and return that data to your controllers. You can do something like this:
How to make multiple http requests?
Don't try to pass in $scope. Just send the post id to the service and return the data you need.
As #tpie and #charlietfl already mentioned, the current approach (passing $scope as parameter to the service) doesn't work. Another alternative to what tpie suggested (caching the posts data in the service) might be using resolve and promises:
Service code
.service('FreshlyPressed', function($q, $http) {
return {
getBlogs: function() {
var deferred = $q.defer();
$http.jsonp('https://public-api.wordpress.com/rest/v1.1/freshly-pressed?callback=JSON_CALLBACK')
.success(function(result) {
deferred.resolve(result.posts);
});
return deferred.promise;
},
get: function (postId, posts) {
/* snipped, this wasn't the problematic part */
}
}
})
This won't cache the posts result in your service, which might be a downside if the $http call you are making is heavy, but using promises is a nice way of setting up asynchronous requests.
Then corresponding state config
.state('tabs', {
url: "/tabs",
abstract: true,
templateUrl: "tabs.html"
})
.state('tabs.news', {
url: "/news",
views: {
'tab-news': {
templateUrl: "tab-news.html",
controller: 'NewsCtrl'
}
},
resolve: {
posts: function (FreshlyPressed) {
return FreshlyPressed.getBlogs();
}
}
})
.state('tabs.post-detail', {
url: '/news/:postId',
views: {
'tab-news': {
templateUrl: 'tab-post-detail.html',
controller: 'PostDetailCtrl'
}
},
resolve: {
posts: function (FreshlyPressed) {
return FreshlyPressed.getBlogs();
}
}
})
This will invoke the getBlogs function in your service and wait for the promise to be resolved. After that, you can inject the resolved posts variable into your controllers:
and finally controllers
.controller('NewsCtrl', function($scope, $ionicLoading, FreshlyPressed, posts) {
$scope.posts = posts;
$scope.doRefresh = function() {
FreshlyPressed.getBlogs()
.then(function (posts) {
$scope.posts = posts;
});
}
});
Here we can set up the $scope.posts variable directly using the resolved posts variable. The doRefresh function needs then to be modified so that it will invoke the service function and after the promise is resolved, set the $scope.posts data accordingly.
.controller('PostDetailCtrl', function($scope, $stateParams, FreshlyPressed, posts) {
$scope.post = FreshlyPressed.get($stateParams.postId, posts);
});
And here we give the service get function the resolved posts variable as parameter, as in this case the service isn't caching that data.
This isn't problem-free approach, for example consider following scenario: you get one set of posts data into your main controller. Then, there are new posts posted into the wordpress you are querying, before your user clicks on a title. This might cause the PostDetailCtrl to receive a new set of posts data, that doesn't any longer contain the certain post that your user clicked.
I think this is anyway a viable alternative, and at least a bit of food for thought.

How can I pass params with AngularJS $resource.query?

At the moment, the url localhost/view/titles will use the route, controller and service below, and the server will return a list of all title objects. How do I extend the service to allow for additional query params, such as a result limit etc?
// main app module with route
var app = angular.module('app', ['ngResource']).
config(function ($routeProvider, $locationProvider) {
$routeProvider.when(
'/view/:obj/:limit',
{
templateUrl: '/static/templates/titles.html',
controller: 'titlesController'
}
)})
// list service
var listService = app.factory('listService', function ($q, $resource) {
return {
getList: function (obj) {
var deferred = $q.defer();
$resource('/api/view/' + obj).query(
function (response) {
console.log('good')
deferred.resolve(response);
}
,
function (response) {
console.log('bad ' + response.status)
deferred.reject(response);
}
)
return deferred.promise;
}
}
}
)
// controller
var titlesController = bang.controller('titlesController', function($scope, listService, $routeParams){
$scope.titles = listService.getList($routeParams.obj);
})
Below is the sample code:
angular.module('phonecatServices', ['ngResource']).
factory('Phone', function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
});
This is a broader answer to the question of how to pass params to your backend api with a query string using the ngResource module since I couldn't find straight forward instructions anywhere else.
ngResource Setup:
Install the ngResource package from the command line with bower or npm bower install angular-resource.
In the head element of the index.html page add the angular-resource script
<script src="lib/angular-resource/angular-resource.min.js"></script>
js/app.js: Add the dependencies. I'm leaving out the routes since I use ui-router which is a separate topic.
angular.module('app', ['app.controllers', 'app.services', 'ngResource'])
The view: templates/list.html
<input type="search" ng-model="filters.title" placeholder="Search">
<button ng-click="searchList(filters)">Submit</button>
<div ng-repeat="item in list">
<p>{{item.title}} - {{item.description}}</p>
</div>
The controller: js/controllers.js
.controller('ListCtrl', function($scope, ListService) {
$scope.searchList = function(filters){
$scope.filters = { title: '' }; //This will clear the search box.
$scope.list = ListService.query({title: filters.title});
}
})
The factory: js/services.js. Assumes you also will be doing get requests by the item id. If not leave out /:id, {id: '#id'}
.factory('ListService', function($resource) {
return $resource('http://localhost:3000/api/view/:id', { id: '#id' });
})

AngularJS - $http POST with Rails 3.2.3

I'm building a simple Contact Management app with Crud using AngularJS 1.0.0rc8.
Getting a list of currently existing contacts is no problem, but while attempting to save a new Contact to the server, a new row is created - complete with the correct id, created_at, and updated_at values - but the rest of the models data is ignored.
Here is a screenshot to show what I mean:
As you can see, numbers 4 and 5 were given the Id's but first_name, last_name, and phone_num were not saved to the database.
I am using a $scope.addContact function within the Controller that deals with the object.
Here is the entire code for the Contact List Controller:
'use strict';
function ContactListCtrl($scope, $http) {
$http.get('/contacts').success(function(data) {
$scope.contacts = data;
});
$scope.addContact = function(data) {
$http.post('/contacts/', data).success(function(data) {
console.log(data);
data.first_name = $("#new_contact_first_name").val();
data.last_name = $("#new_contact_last_name").val();
});
this.newFirstName = '';
this.newLastName = '';
};
};
After clicking 'Save' on the new-contact.html partial, the Object is logged to the Console, if I inspect its contents, than sure enough the values are collected - notice Jimi Hendrix is there:
Here is the form as it appears in the new-contact.html template:
<form id="contact_form" ng-submit="addContact()">
<input type="text" id="new_contact_first_name" name="newContactFirstName" ng-model="newFirstName" placeholder="First Name"></br>
<input type="text" id="new_contact_last_name" name="newContactLastName" ng-model="newLastName" placeholder="Last Name"></br>
<input type="button" id="contact_submit_btn" value="Add Contact" class="btn btn-primary">
</form>
The addContact() function is fired after the form is submitted with JQuery:
$(document).ready(function(){
$("#contact_submit_btn").click(function(){
$("#contact_form").submit();
});
});
(Something tells me that I may not be using the ng-model attributes correctly.)
Any ideas on where I am going wrong with this? Or ideas on how I can better go about implementing this design?
Thanks.
UPDATE BELOW:
Here is my entire updated controller code - with help from Sathish:
// contacts controllers
'use strict';
function ContactListCtrl($scope, $http, Contacts) {
$scope.contacts = Contacts.index();
$scope.addContact = function() {
var newContact = {
first_name: $scope.newContactFirstName,
last_name: $scope.newContactLastName
};
var nc = new Contacts({ contact: newContact });
nc.$create(function() {
$scope.contacts.push(nc);
// now that the contact is saved, clear the form data
$scope.newContactFirstName = "";
$scope.newContactLastName = "";
})
}
};
ContactListCtrl.$inject = ['$scope', '$http', 'Contacts'];
function ContactDetailCtrl($scope, $routeParams, Contacts) {
$scope.contact = Contacts.get( {contact_id: $routeParams.contact_id} );
}
ContactDetailCtrl.$inject = ['$scope', '$routeParams', 'Contacts'];
I am now receiving the error: Unknown Provider for Contacts. Here is a screenshot of the error
Ok, I managed to fix that error by providing a ngResource to the main App file. Here's what it looks like:
// main app javascript file
'use strict';
angular.module('contactapp', ['ngResource']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/contacts', {template: 'assets/app/partials/contact-list.html', controller: ContactListCtrl}).
when('/contacts/new', {template: 'assets/app/partials/new-contact.html', controller: ContactListCtrl}).
when('/contacts/:contact_id', {template: 'assets/app/partials/contact-detail.html', controller: ContactDetailCtrl}).
otherwise({redirectTo: '/contacts'});
}]);
I am receiving a new error: WARNING: Can't verify CSRF token authenticity
Alright, managed to fix that problem too by adding a callback to the API controller:
Rails shows "WARNING: Can't verify CSRF token authenticity" from a RestKit POST
Now I am back to the original problem. When the create method is called, a new row is saved to the database, but the models data is not.
Awesome... finally got this thing working.
The problem was the $scope.addContact function. It was using the 'name' of the input instead of the ng-model binding called 'newFirstName' and 'newLastName' that resides in the template.
Here's what the updated function looks like:
$scope.addContact = function() {
var newContact = {
first_name: $scope.newFirstName,
last_name: $scope.newLastName
};
var nc = new Contacts({ contact: newContact });
nc.$create(function() {
$scope.contacts.push(nc);
// now that the contact is saved, clear the form data
$scope.newFirstName = "";
$scope.newLastName = "";
})
}
This can be better implemented using a Contacts service. Please define a Contacts service in app/assets/javascripts/services.js.erb as shown below:
var servicesModule = angular.module('<your app name>',
[<list of modules needed by this app>]);
servicesModule.factory('Contacts', function($resource) {
var ContactsService = $resource('/contacts/:contact_id', {}, {
'create': { method: 'POST' },
'index': { method: 'GET', isArray: true },
'update': { method: 'PUT' },
'destroy': { method: 'DELETE' }
});
return ContactsService;
});
Change the addContact method in the controller as shown below:
function ContactListCtrl($scope, $http, Contacts) {
...
...
...
$scope.addContact = function () {
var newContact = {
first_name: $scope.newContactFirstName,
last_name: $scope.newContactLastName
};
var nc = new Contacts({ contact: newContact });
nc.$create(function() {
$scope.contacts.push(nc);
// now that the contact is saved, clear the form data.
$scope.newContactFirstName = "";
$scope.newContactLastName = "";
});
};
...
...
...
}
ContactListCtrl.$inject = ['$scope', '$http', 'Contacts'];
In addition to this, you can simplify the $http.get(...) part also. You can use Contacts.index();
Note:
If you gave ng-app="MyAppName" then please replace <your app name> with MyAppName.
<list of modules needed by this app> needs to the replaced by a comma-separated list of strings representing any modules needed by your application.
Check the attr_accessible on your model. With new 3.2.3 rails all model attributes became protected from mass-assignment by default.

Categories

Resources