- Read Tutorial
- Watch Guide Video
This is going to be a really cool guide in this guide we are going to finally be able to create proposals in our Rails app from our angular app and to do this. I want to ask you a question and I want you to be completely honest on the way you answer this. I want you to pause the video and I want you to think about a question which is because of this feature we want to build. What is the very first step that we need to take? So I want you to think about that and then pause the video come back and then we're going to walk through exactly how to build this kind of feature.
If you paused the video. Welcome back. And obviously I can't hear your answer in real time but you know what your answer was. So I want you to have thought about that. And the reason why I wanted you to go through that exercise is because it's really easy in tutorials like this to simply follow along. And the problem with that is you're not being proactive with what you're working through. So if you weren't following along with this tutorial and you were having to do this by yourself it would be a completely different experience but you'd actually learn it even more. Obviously, you need to find out what you need to do in order to in order to know what to build in. But hopefully that you've seen that any time we have created a connection with an API with any of the API that we've connected to we started off with our service. So it if you didn't if that wasn't your answer and that wasn't what popped in your head that's perfectly fine. It was more that I wanted to show you that it's important when you're going along with these kind tutorials to actually think a few steps ahead. So think about what you would do if you were the one giving the tutorial right now and you are the one who was leading it and other people were following. Think about what steps you would take in order to build a feature. It doesn't matter if your answer is right or not just the fact that you're proactively thinking about it is going to be very helpful. So that was just a little kind of just a little tidbit on how to learn programming better just because it is too easy to fall into kind of that cycle of just watching what the instructors doing on the screen and you're not going to remember it quite as much as if you're proactive with your thinking. So like I said we're going to start off in the proposal service so I'm going to open up proposal.service.ts
. And what we're going to do here is create a new function. So this proposal service is going to create a proposal. So this is going to be our API connector and I'm going to say createProposal
and we're going to pass in a proposal now inside of this. This is all of the API logic that's going to connect our angular service with our rails application. So if you know how Rails applications work you know that we create a post request in order to generate a new record. And that's exactly what we're going to do here. However it's not quite as easy as just saying proposal.post or post and then send in proposal because it's an API and especially because it's one where we're going out and we're sending data rails. The Rails application is going to expect more information than just the proposal by itself. So let's talk about what it's going to and expect it's going to expect some headers and the headers are going to be something that are brought in from. I brought them up already here and this is going to come from our Http
library. So I'm going to say new Headers
and inside of this Headers
is a hash in HTTP. So or you can think of is a javascript object. So what's inside the headers is going to be a content type or it will be content dash type and then a semi-colon followed by another string which is application/json
and that is that should be all we need there.
createProposal(proposal) { let headers = new Header({ 'Content-Type': 'application/json})' }
Let's see why Angular is complaining about this, value of typeof header is not callable did you mean to include new? and yes I did. I love when the error messages are so explicit they actually tell you how to fix your problem. It'd be nice if all their messages were that good. So we have our headers and what this is going to do is when we create our JSON request when when we contact the rails API it's expecting to have headers and what this is going to do is it's going to let the rails app know hey I am sending JSOn data that's all it's there for and right now we're not actually contacting the API right now we're simply creating a variable to store those.
Next we're going to set our options. So inside of options I'm going to give new
and we're going to have RequestOptions
. Request options is something I already pulled in up top from the Http
library just like header's because I knew we were going to need them now inside of this. This is where we're actually going to pass our headers. So here we're going to say headers: headers
.
let options = new RequestOptions({ headers: headers });
Now that seems kind of redundant. Don't worry it is. It's not something that is really as much a programming practice as just a convention that you have to follow so that the Rails application gets the type of data that it expects. So that's just some rules that you follow whenever you're contacting and sending a request to an API. And so next thing that we're going to do now that we have our options is now we're actually going to do the work. So I'm going to say return this.http.post
and with post. This is our post request this is the cool stuff. This is everything we're doing. So I'm going to say (this.proposalsUrl)
. So this is where we're calling the API. That's the first argument. So post takes that as a first argument and next is the actual data we're sending. So here I'm going to create a JSON object here is going to be JSON.stringify(proposal)
return this.http.post(this.proposal, JSON.stringify(proposal))
So what in the world am I doing here. I'm going to just kind of sit back and explain this first. So post is a function just like any other function. This .proposalsUrl
is our API connection. So we're saying that this is the API that we want you to send this post request to then from here we're saying that I want you I'm going to pass in the proposal but the application wouldn't know what to do with a regular proposal.
So we have to kind of clean it up a little bit and that's what we're doing here with JSON.stringify
. This is just going structure the data of our proposal so that it's something that the Rails application can actually interpret and parse once it gets it. So that's the second argument the next argument is going to be a hash or object and it's going to just be our headers
again. So it's going to be
headers: headers
and that is everything that we need there.
So that is our full post request and these are the three arguments we're passing to the function. Now as you might have guessed we are going to use the .map()
method so the .map()
method is going to, just like it did in our getRequests
. It's going to take a function
createProposal(proposal) { let headers = new Headers({ 'Content-Type': 'application/json'}); let options = new RequestOptions({ headers: headers }); return this.http.post(this.proposalsUrl, JSON.stringify(proposal), { headers: headers}).map((res: Response) => res.json()); }
So this is going to be our information to let us know that yes this was a successful request or no there was an error or something like that. So that is everything we need on createProposal
. And so far no errors so we're good on that side. Now that is our service.
And now let's move on to our actual component (proposal-new.component.ts
)because this is where we're going to be putting our actual data. So that was a service that was kind of our generic connection to the API. Now we have to create our function that's going to connect to that. So as you might have guessed we do not have a call to our proposal service yet. So let's do that here.
import { ProposalService } from './proposal.service';
And then we want to add a list of providers
providers: [ProposalService]
And that is the first part of what we need. And additionally, we're going to have to bring in as you might have also guessed an observable and I'm going to slide this in right here so I'm going to say
import { Observable } from 'rxjs/Rx'';
And now after that, we're going to move down. And we now need to do some dependency injection. So here let's create a constructor and our constructor is going to not do anything besides manage our dependency injection. So I'm going to say
constructor( private proposalService: ProposalService ) {}
Just like you may have guessed. So everything here should be relatively familiar with what we've seen so far. We also already have a proposal and we have a submitted flag here and that's pretty much everything we need in order to get started. So the next thing that we need to do is come down and now let's actually create our function. So this is going to be
createProposal(proposal) { this.submitted = true }
And if you're wondering what this means if you remember to the last guide we created a submitted variable and we put it as an item inside of our form. So that's what's going to make our button disappear when a form has been submitted so what this is going to do is every time that a form is submitted it's going to take that and it's going to say this submitted is going to now be true which is going to hide that button for us dynamically. So that's the first part that doesn't actually have anything to do with data it's just going to you know show or hide something on the app. Now I'm going to say
createProposal(proposal) { this.submitted = true; this.proposalService.createProposal(proposal) .subscribe( data => { return true }, error => { console.log("Error saving proposal"); } )
So this is our function that's brought in from the service. And now we want to call subscribe and subscribe as you are probably now relatively familiar with subscribe is going to take some different arguments. But the first one is going to be a is going to be a function. And all this is really doing is saying that we're saying that if the data comes back we're wanting this to be mapped and to say that everything is good to go and it got returned true
which means that it got submitted properly. That is on a successful request. Now we also have to take into account what would happen if an error occurs. And let me put this on a couple lines just so it's easier to read so I'm going to say data is going to return true. And then a comma which is going to separate our error. So now if an error comes through then we want to console log something out. So we could say console log and say "Error saving proposal"
. And then we want to return an observable so I'm going to return an observable, throw error and then we could deal with this however we saw fit. OK. So let me just kind of get all of these lined up, we have our error that is lined up with the curly brackets subscribe is lined up with this parentheses right here. And we also need to close that off with a semi colon. And I believe that is all we need for the function.
createProposal(proposal) { this.submitted = true; this.proposalService.createProposal(proposal) .subscribe( data => { return true }, error => { console.log("Error saving proposal"); return Observable.throw(error); } );
Now that's that's all we need on the function but that's not the rest of the application it still won't work. And the reason for that is because we need to finish off what we're doing in the form. So the form itself needs to actually submit the value. And if you're coming from a HTML background or something like that. What are you is going to look very different to you but it's actually a clean way of being able to manage forms. So if I scroll all the way up. ( we are now in the proposal-new.component.html
) To the very top of where our form tag is here this is where we are going to be able to place this call. So I'm going to say form and then right afterwards I'm going to create an action here. So this is going to listen for what we're going to be doing and what it's listening for is ngSubmit
. And what that means is ngSubmit
means it's looking for someone to press the submit button. In this case its the generate proposal button. And inside of this we can pass in what we want to happen.
So this is kind of cool because you think of forms only really being used to submit data but because angular is so flexible you could have this do anything you could have the button you trigger some kind of calculation to get spun off of or you know you could have it do anything that you really want it. In this case we want to create a proposal and we're going to pass in the proposal. And this is going to take all the data and it is going to submit it in the form if we did everything right.
<form (ngSubmit)="createProposal(proposal)" #proposalForm="ngForm">
So hit save. And so far so good. We don't have any errors. Now let's come look at our full list of proposals. We have zero all the way through Google. Let's now come to New proposal and let's try our luck with Yahoo. Followed by anything you want. There Ruby on Rails for the service estimated hours 23 hourly rate 80 weeks to complete 4 will leave that optional. Notice our button is now good to go. If I click generate proposal our button goes away. So that means that it definitely did go inside of that create proposal function. And now if I click on proposals if I scroll down look at that that created a record in our API so it could created a record in our Rail's API and it immediately sent it back in this database query. So now we have access to it.
So fantastic job if you went through that you now know how to create records not just query them. We learned how we can query all the records we learned we can query a single record just like our show page. And now you know how to use a form to connect to an API and submit data to a remote application. So fantastic job in the next guide we're going to go through. The last thing that we're going to be implementing right here which is going to be the the alert that's going to get can give a little success message and from there we only have one last feature which is the email feature that we're going to add to the rails microservice.