I\'m new to Angular. I\'ve tried everything I know how and Google searches have surprisingly few tutorials on this particular question. Here\'s the last code I tried:
<Angular has a feature called services
which acts as a model for the application. It's where I'm communicating with my Rails backend:
services/article.js
app.factory('Article', function($resource) {
return $resource('http://localhost:3000/articles/:id', { id: '@id'},
{
'update': { method: 'PUT'}
});
});
Even though the :id
is specified on the end, it works just as well for going straight to the /articles
path. The id
will only be used where provided.
The rest of the work goes into the controller:
controllers/articles.js
app.controller('NewPostCtrl', function($scope, Article) {
$scope.newPost = new Article();
$scope.save = function() {
Article.save({ article: $scope.article }, function() {
// Optional function. Clear html form, redirect or whatever.
});
};
});
Originally, I assumed that the save()
function that's made available through $resources
was somewhat automatic. It is, but I was using it wrong. The default save()
function can take up to four parameters, but only appears to require the data being passed to the database. Here, it knows to send a POST
request to my backend.
views/articles/index.html
<form name="form" ng-submit="save()">
<input type="text" id="title" ng-model="article.title">
<input type="text" id="body" ng-model="article.body">
<input type="submit" value="Submit">
</form>
After getting the service
setup properly, the rest was easy. In the controller, it's required to create a new instance of the resource (in this case, a new article). I created a new $scope
variable that contains the function which invokes the save
method I created in the service
.
Keep in mind that the methods created in the service can be named whatever you want. The importance of them is the type of HTTP request being sent. This is especially true for any RESTful app, as the route for GET
requests is the same as for POST
requests.
Below is the first solution I found. Thanks again for the responses. They were helpful in my experiments to learn how this worked!
Original Solution:
I finally fixed it, so I'll post my particular solution. However, I only went this route through lack of information how to execute this through an angular service
. Ideally, a service would handle this kind of http request. Also note that when using $resource
in services, it comes with a few functions one of which is save()
. However, this also didn't work out for me.
$http
: https://docs.angularjs.org/api/ng/service/$http$resource
: https://docs.angularjs.org/api/ngResource/service/$resourcearticles.js controller
app.controller('FormCtrl', function($scope, $http) {
$scope.addPost = function() {
$scope.article = {
'article': {
'title' : $scope.article.title,
'body' : $scope.article.body
}
};
// Why can't I use Article.save() method from $resource?
$http({
method: 'POST',
url: 'http://localhost:3000/articles',
data: $scope.article
});
};
});
Since Rails is the backend, sending a POST
request to the /articles
path invokes the #create
method. This was a simpler solution for me to understand than what I was trying before.
To understand using services
: the $resource
gives you access to the save()
function. However, I still haven't demystified how to use it in this scenario. I went with $http
because it's function was clear.
Sean Hill has a recommendation which is the second time I've seen today. It may be helpful to anyone else wrestling with this issue. If I come across a solution which uses services, I'll update this.
Thank you all for your help.
Until your input fields are blank, no value is stored in model and you POST empty article object. You can fix it by creating client side validation or set default empty string value on needed fields before save.
First of all you should create new Article object in scope variable then pass newPost
by params or access directly $scope.newPost
in addArticle
fn:
app.controller('ArticlesCtrl', function($scope, Article) {
$scope.articles = Article.query();
$scope.newPost = new Article();
$scope.addArticle = function(newPost) {
if (newPost.title == null) {
newPost.title = '';
}
// or if you have underscore or lodash:
// lodash.defaults(newPost, { title: '' });
Article.save(newPost);
};
});
If you want use CRUD operations you should setup resources like below:
$resource('/articles/:id.json', { id: '@id' }, {
update: {
method: 'PUT'
}
});
I've worked a lot with Angular and Rails, and I highly recommend using AngularJS Rails Resource. It makes working with a Rails backend just that much easier.
https://github.com/FineLinePrototyping/angularjs-rails-resource
You will need to specify this module in your app's dependencies and then you'll need to change your factory to look like this:
app.factory('Article', function(railsResourceFactory) {
return railsResourceFactory({url: '/articles', name: 'article');
});
Basically, based on the error that you are getting, what is happening is that your resource is not creating the correct article
parameter. AngularJS Rails Resource does that for you, and it also takes care of other Rails-specific behavior.
Additionally, $scope.newPost
should not be Article.save()
. You should initialize it with a new resource new Article()
instead.