I am doing a Vue 3 practice together with Django Rest Framework, what I am trying to do is a token authentication validation, a user logs in, a token is going to be generated, but I run into a problem and it is that when at moment of logging in is done correctly and I am able to obtain the generated token, the problem is that when reloading the page the token is no longer in the vue application, a possible solution that I decided is to make the token save in local storage, but i think it is not the correct solution.
This is my Login.vue:
<template>
<h2>login</h2>
<form method="POST" #submit.prevent="sendData" autocomplete="off">
<input
type="text"
placeholder="Nombre de Usuario"
v-model.trim="username"
/>
<input
type="password"
placeholder="ContraseƱa de Usuario"
v-model.trim="password"
/>
<button type="submit">enviar</button>
</form>
</template>
<script>
import { ref } from '#vue/reactivity';
import { watchEffect } from '#vue/runtime-core';
export default {
setup() {
const username = ref('');
const password = ref('');
const token = ref('');
const sendData = () => {
fetch(`http://localhost:8000/auth-token/`, {
method: 'POST',
body: JSON.stringify({
username: username.value,
password: password.value,
}),
headers: {
'Content-Type': 'application/json',
},
})
.then((res) => res.json())
.catch((error) => console.error('Error:', error))
.then((response) => {
token.value = response.token;
});
};
watchEffect(() => localStorage.setItem('Token', token.value));
return {
username,
password,
sendData,
};
},
};
</script>
Here is one of my latest answer on the question: https://stackoverflow.com/a/66872372/8816585
TLDR: you only have a few possibilities to persist the data on the frontend but using localStorage/cookies/IndexedDB is totally fine for this purpose.
Also, making a call to the backend at the start of your app is a good idea too, especially if the payload is a bit heavy (you send some JWT, and get a load of personal infos).
Here is a list of packages that may help you persist data on the frontend: https://github.com/vuejs/awesome-vue#persistence
Related
I've the following setup:
local domain entries in /etc/hosts:
127.0.0.1 app.spike.local
127.0.0.1 api.spike.local
I've created an express server in TypeScript:
const app = express()
app.use(cookieparser())
app.use(
cors({
origin: 'https://app.spike.local',
credentials: true,
exposedHeaders: ['Set-Cookie'],
allowedHeaders: ['Set-Cookie']
})
)
app.get('/connect/token', (req, res) => {
const jwt = JWT.sign({ sub: 'user' }, secret)
return res
.status(200)
.cookie('auth', jwt, {
domain: '.spike.local',
maxAge: 20 * 1000,
httpOnly: true,
sameSite: 'none',
secure: true
})
.send()
})
type JWTToken = { sub: string }
app.get('/userinfo', (req, res) => {
const auth = req.cookies.auth
try {
const token = JWT.verify(auth, secret) as JWTToken
console.log(req.cookies.auth)
return res.status(200).send(token.sub)
} catch (err) {
return res.status(401).json(err)
}
})
export { app }
I've created a simple frontend:
<button
id="gettoken"
class="m-2 p-1 rounded-sm bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-600 focus:ring-opacity-50 text-white"
>
Get Token
</button>
<button
id="callapi"
class="m-2 p-1 rounded-sm bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-600 focus:ring-opacity-50 text-white"
>
Call API
</button>
<div class="m-2">
Token Response Status Code:
<span id="tokenresponse" class="bg-green-100"></span>
</div>
<div class="m-2">
API Response: <span id="apifailure" class="bg-red-100"></span
><span id="apiresponse" class="bg-green-100"></span>
</div>
<script type="text/javascript">
const tokenresponse = document.getElementById('tokenresponse')
const apiresponse = document.getElementById('apiresponse')
const apifailure = document.getElementById('apifailure')
document.getElementById('gettoken').addEventListener('click', async () => {
const response = await fetch('https://api.spike.local/connect/token', {
credentials: 'include',
cache: 'no-store'
})
tokenresponse.innerHTML = response.status
})
document.getElementById('callapi').addEventListener('click', async () => {
const userInfoResponse = await fetch('https://api.spike.local/userinfo', {
credentials: 'include',
cache: 'no-store'
})
if (userInfoResponse.status === 200) {
const userInfo = await userInfoResponse.text()
apifailure.innerHTML = ''
apiresponse.innerHTML = userInfo + ' #' + new Date().toISOString()
} else {
const failure = (await userInfoResponse.json()).message
console.log(failure)
apiresponse.innerHTML = ''
apifailure.innerHTML = failure
}
})
</script>
When running the UI on https://app.spike.local and the API on https://api.spike.local both using self certificates and browsing the UI, I can successfully request a token in a cookie and subsequently use this token via cookie being sent automatically for the API call in Chrome and Firefox.
However, on Safari on macOS (and iOS) the Cookie isn't being sent in the subsequent API call.
As can be seen,
Cookie settings are SameSite=None, HttpOnly, Secure, Domain=.spike.local.
CORS has no wildcards for headers and origins and exposes and allows the Set-Cookie header as well as Access-Control-Allow-Credentials.
on client side, fetch options include credentials: 'include'
As said, both API and UI are served over SSL with valid self signed certificates.
When disabling Preferences/Privacy/Prevent cross-site tracking in Safari, everything works fine. But this not an option for this scenario in production.
What am I doing wrong here?
Solved it by changing the TLD to .com instead of .local.
The hint has been in this comment.
Hello so I am working on a Django and React project I am fairly new to the domain I can't understand why this is not working, so I would love to make a POST request to my API and save the contents to the database and the after then the function that is currently working to retrieve contents in my DB will do its work to update the website.
So after I made the POST request this is the response I get when I console logged:
Response { type: "cors", url: "http://127.0.0.1:8000/api/upload-lecture/", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, body: ReadableStream, bodyUsed: false }
I personally thought after getting a status code of 200 everything is fine but when I go check the database the is nothing new that was added.
I even checked the with Django logs that were coming and this is what I got too:
"POST /api/upload-lecture/ HTTP/1.1" 200 108
So I do not understand why the contents are not in the database.
Code to my Api: Upload method:
#api_view(['POST'])
def videoUpload(request):
serializer = LectureVideosSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
Code to React:This is where I was trying to make the POST request
import React, { useState } from 'react';
const VideoUploadForm = () =>{
const [lecturer, setLecturer] = useState('');
const [module, setModule] = useState('');
const [video, setVideo] = useState();
const [date, setDate] = useState('');
const newVideo = () =>{
const uploadData = new FormData();
uploadData.append('lecturer', lecturer);
uploadData.append('module', module);
uploadData.append('video', video);
uploadData.append('date', date);
fetch('http://127.0.0.1:8000/api/upload-lecture/', {
method:'POST',
body:uploadData
}).then(response => console.log(response)).catch(error => console.log(error))
}
const handleLecturer = (e) =>{
setLecturer({
lecturer: e.target.value
})
}
const handleModule = (e) =>{
setModule({
module: e.target.value
})
}
const handleVideo = (e) =>{
setVideo({
video: e.target.files[0]
})
}
const handleDate = (e) =>{
setDate({
date: e.target.value
})
}
return(
<div className="form__container">
<label>
Lecturer:
<input type="text" onChange={handleLecturer} placeholder="Lecturer uploading"/>
</label>
<label>
Module:
<input type="text" onChange={handleModule} placeholder="Module of Video Uploaded"/>
</label>
<label>
Video:
<input type="file" onChange={handleVideo}/>
</label>
<label>
Date:
<input type="text" onChange={handleDate} placeholder="YY-mm-dd"/>
</label>
<button onClick={() => newVideo()}>Upload Video</button>
</div>
)
}
export default VideoUploadForm;
This is the error that I am getting when I print out the serializers errors
[*] Error:{'video': [ErrorDetail(string='The submitted data was not a file. Check the encoding type on the form.', code='invalid')], 'date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY-MM-DD.', code='invalid')]}
How can I resolve this
For the date make sure you have the format mentioned in the error,for file upload,I usually use MultiPartParser,you can set that up using a parser_classes decorator.
I am trying to send post data to a django Restful API using vuejs. here is the code I have so far:
<script>
import axios from 'axios'
import VueCookies from 'vue-cookies'
//3RD ATTEMPT
VueCookies.set("csrftoken","00000000000000000000000000000000");
// # is an alias to /src
export default {
name: "Signup",
components: {},
data: () => {
},
methods: {
sendData(){
// 2ND ATTEMPT
// $cookies.set("csrftoken", "00000000000000000000000000000000");
axios({
method: 'post', //you can set what request you want to be
url: 'https://localhost:8000/indy/signup/',
data: {
csrfmiddlewaretoken: "00000000000000000000000000000000",
first_name: "wade",
last_name: "king",
email: "wade%40mail.com",
password1: "05470a5bfe",
password2: "05470a5bfe"
},
// 1ST ATTEMPT
// headers: {
// Cookie: "csrftoken= 00000000000000000000000000000000"
// },
withCredentials: true
})
}
}
</script>
I have a button which executes the sendData() method on a click. The code uses the axios library to send a post request to the django API running on http://localhost:800/indy/signup/
The problem with just sending a post request to the API is that it will get blocked in order to prevent Cross Site Response Forgery (CSRF), I dont quite understand CSRF but I know if the csrftoken is set as a cookie and has the same value as the csrfmiddlewaretoken then the post should go through to the API.
You can see my attempts to set the cookie in the code I provided
1ST ATTEMPT)
headers: {
Cookie: "csrftoken= 00000000000000000000000000000000"
},
Here I'm trying to set the cookie directly in the header. When I click send I get an error in my browser console saying refused to set unsafe header "Cookie"
2ND ATTEMPT)
$cookies.set("csrftoken", "00000000000000000000000000000000");
Here I'm trying to set the cookie using the vue-cookies module. When i click send I get the following error, net::ERR_SSL_PROTOCOL_ERROR
3RD ATTEMPT)
VueCookies.set("csrftoken","00000000000000000000000000000000");
Here I'm trying to set a global cookie using the vue-cookies module. When I click send I get the same error as attempt 2
IMPORTANT:
However when I send post data to the API from my terminal using the following curl command, it works perfectly
curl -s -D - -o /dev/null \
-H 'Cookie: csrftoken= 00000000000000000000000000000000' \
--data 'csrfmiddlewaretoken=00000000000000000000000000000000&first_name=wade&last_name=king&email=wade%40mail.com&password1=05470a5bfe&password2=05470a5bfe' \
http://localhost:8000/indy/signup/
my main question is How can I replicate this curl request using vuejs? I've looked all over on line and none of the tutorials deal with setting cookies.
I posted this question some time ago, I have managed to work around it by running the vue frontend on the same network as the django backend. Follow this tutorial for instructions: integrating vuejs and django
Once I had the application set up I was able to set the cookies much more cleanly using :
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
Here is my login page for example
<template>
<div class = "container">
<h2>Sign In</h2>
<b-form v-on:submit.prevent="submit()">
<b-form-group id="signin" label="">
<!-- dynamic error message -->
<p class="loginErr" v-if="logErr">Incorrect Username or Password</p>
<b-form-input
id="signin-email"
v-model="username"
placeholder="Email"
required
></b-form-input>
<b-form-input
id="signin-password"
v-model="password"
placeholder="Password"
required
type="password"
></b-form-input>
</b-form-group>
<b-button v-if="!loading" type="submit" variant="primary">Submit</b-button>
<b-spinner v-if="loading"></b-spinner>
</b-form>
</div>
</template>
<script>
import axios from 'axios'
import Vue from 'vue'
export default {
data: ()=>{
return{
loading: false,
logErr: false,
username:'',
password:'',
next: '%2Findy%2Fprofile%2F'
}
},
created: function(){
},
methods: {
submit(){
var vm = this;
vm.loading = true;
var dataStr = 'username='+vm.username+'&password='+vm.password
//set the csrf tokens so django doesn't get fussy when we post
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
axios.post('http://localhost:8000/api/signin/', dataStr)
.then(function (response) {
vm.loading = false;
//determine if indy accepts the login request
var res = response.data
console.log(response.data)
if(!res.login){
vm.logErr = true;
}else{
vm.redirect('home');
}
})
.catch(function (error) {
//currentObj.output = error;
});
},
redirect(path) {
this.$router.push('/' + path);
}
}
}
</script>
<style>
.loginErr{
color: orange;
}
</style>
Problem
I have a /login route that uses ember-simple-auth to implement authentication. During testing ember-cli-mirage is used to mock the backend. The user logs in by providing their email address and password.
In total I have 4 acceptance tests for this route, similar to the test below:
test('should show error message for invalid email', function(assert) {
visit('/login');
fillIn('input#email', 'invalid-email');
fillIn('input#password', 'invalid-password');
click('button.button');
andThen(function() {
assert.equal(find('div.notification').text(), "Invalid email/password");
});
});
When I run the tests using ember t only the first test in the file fails. If I comment this test out, the next one fails, and so on. If I run the tests in server mode with ember t -s the same test fails; however, when I press enter to re-run the tests, all the tests pass.
The failure message is always the same, shown below:
not ok 7 PhantomJS 2.1 - Acceptance | login: should show error message for invalid email
---
actual: >
expected: >
Invalid email/password
stack: >
http://localhost:7357/assets/tests.js:22:19
andThen#http://localhost:7357/assets/vendor.js:48231:41
http://localhost:7357/assets/vendor.js:48174:24
isolate#http://localhost:7357/assets/vendor.js:49302:30
http://localhost:7357/assets/vendor.js:49258:23
tryCatch#http://localhost:7357/assets/vendor.js:68726:20
invokeCallback#http://localhost:7357/assets/vendor.js:68738:21
publish#http://localhost:7357/assets/vendor.js:68709:21
http://localhost:7357/assets/vendor.js:48192:24
invoke#http://localhost:7357/assets/vendor.js:10892:18
flush#http://localhost:7357/assets/vendor.js:10960:15
flush#http://localhost:7357/assets/vendor.js:11084:20
end#http://localhost:7357/assets/vendor.js:11154:28
run#http://localhost:7357/assets/vendor.js:11277:19
run#http://localhost:7357/assets/vendor.js:32073:32
http://localhost:7357/assets/vendor.js:48783:24
Log: |
After all the tests have run, test emits an exception:
# tests 60
# pass 59
# skip 0
# fail 1
Not all tests passed.
Error: Not all tests passed.
at EventEmitter.getExitCode (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/lib/app.js:434:15)
at EventEmitter.exit (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/lib/app.js:189:23)
at /home/jon/projects/jonblack/wishlist-web/node_modules/testem/lib/app.js:103:14
at tryCatcher (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:510:31)
at Promise._settlePromise (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:567:18)
at Promise._settlePromise0 (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:612:10)
at Promise._settlePromises (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/promise.js:691:18)
at Async._drainQueue (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/async.js:138:16)
at Async._drainQueues (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/async.js:148:10)
at Immediate.Async.drainQueues (/home/jon/projects/jonblack/wishlist-web/node_modules/testem/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:637:20)
at tryOnImmediate (timers.js:610:5)
at processImmediate [as _immediateCallback] (timers.js:582:5)
It seems odd that this is emitted for tests failing rather than just reporting the test failure, so perhaps it's related.
Running the tests in Firefox and Chromium work, as does running the application in development mode and logging in manually. The problem is limited to phantomjs.
I have other acceptance tests for another route and these all pass. It seems limited to the /login route, suggesting that it is possibly related to authentication.
Debugging
I've tried debugging by adding pauseTest() to the test and "phantomjs_debug_port": 9000 to testem.js but both Firefox and Chromium do nothing when I use the debug console. This might be my lack of experience debugging phantomjs, but I would at least expect it to give me an error - it literally does nothing.
It feels as though there is a timing issue between phantomjs and something, possible ember-simple-auth, in my Ember app.
I'm not that experienced debugging phantomjs problems nor Ember acceptance test failures, so any help is appreciated.
Versions
ember-cli 2.10.0
ember-simple-auth 1.1.0
ember-cli-mirage 0.2.4
Update 1
The button is inside a login-form component:
<form {{action 'login' on='submit'}}>
<p class="control has-icon">
{{input value=email id='email' placeholder='email' class='input'}}
<i class="fa fa-envelope"></i>
</p>
<p class="control has-icon">
{{input value=password id='password' placeholder='password'
type='password' class='input'}}
<i class="fa fa-lock"></i>
</p>
<p class="control">
<button class="button is-success" disabled={{isDisabled}}>Log In</button>
</p>
</form>
The component's login action just calls the passed in login handler:
import Ember from 'ember';
export default Ember.Component.extend({
email: "",
password: "",
isDisabled: Ember.computed('email', 'password', function() {
return this.get('email') === "" || this.get('password') === "";
}),
actions: {
login() {
var email = this.get('email');
var password = this.get('password');
this.attrs.login(email, password);
}
}
});
Which is the authenticate method in the login controller:
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service(),
actions: {
authenticate(email, password) {
this.get('session').authenticate('authenticator:oauth2', email, password).catch((data) => {
this.set('errors', data['errors']);
});
}
}
});
Update 2
As suggested by Daniel I added a delay to the test:
test('should show error message for invalid email', function(assert) {
visit('/login');
fillIn('input#email', 'invalid-email');
fillIn('input#password', 'invalid-password');
click('button.button');
andThen(function() {
Ember.run.later(this, function() {
assert.equal(find('div.notification').text(), "Invalid email/password");
}, 0);
});
});
Using only Ember.run.later the test still failed, but putting that inside the andThen causes it to pass. Have you noticed the bizarre part? The delay is 0 milliseconds.
I still want to find an explanation for this because I don't trust that this will run the same on whatever machine the tests run on.
Update 3
Today I had a surprise: suddenly the tests were working again!
I added a new route with acceptance tests. The route itself is an authenticated route, so the tests use the authenticateSession test helper from ember-simple-auth to authenticate.
when I remove the tests that use this helper, the error returns!.
I'm not sure what this means. It feels like the issue is with ember-simple-auth, but it might also be a giant coincidence that the helper resolves another timing issue.
Down the rabbit hole we go...
Update 4
Below is the configuration for the auth endpoints in ember-cli-mirage:
this.post('/token', function({db}, request) {
var data = parsePostData(request.requestBody);
if (data.grant_type === 'password') {
// Lookup user in the mirage db
var users = db.users.where({ email: data.username });
if (users.length !== 1) {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'invalid_login',
status: '400',
title: 'Invalid email/password',
}]
});
}
var user = users[0];
// Check password
if (data.password === user.password) {
if (!user.active) {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'inactive_user',
status: '400',
title: 'Inactive user',
}]
});
} else {
return new Mirage.Response(200, {
'Content-Type': 'application/json'
}, {
access_token: 'secret token!',
user_id: user.id
});
}
} else {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'invalid_login',
status: '400',
title: 'Invalid email/password',
}]
});
}
} else {
return new Mirage.Response(400, {'Content-Type': 'application/json'}, {
errors: [{
id: 'invalid_grant_type',
status: '400',
title: 'Invalid grant type',
}]
});
}
});
this.post('/revoke', function(db, request) {
var data = parsePostData(request.requestBody);
if (data.token_type_hint === 'access_token' ||
data.token_type_hint === 'refresh_token') {
return new Mirage.Response(200, {'Content-Type': 'application/json'});
} else {
return new Mirage.Response(400, {'Content-Type': 'application/json'},
{error: 'unsupported_token_type'});
}
});
Update 5
Here's my config/environment.js file:
/* jshint node: true */
module.exports = function(environment) {
var ENV = {
modulePrefix: 'wishlist-web',
environment: environment,
rootURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
},
EXTEND_PROTOTYPES: {
// Prevent Ember Data from overriding Date.parse.
Date: false
}
},
APP: {
}
};
if (environment === 'development') {
}
if (environment === 'test') {
// Testem prefers this...
ENV.locationType = 'none';
// keep test console output quieter
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
}
if (environment === 'production') {
ENV.ServerTokenEndpoint = 'http://localhost:9292/token';
ENV.ServerTokenRevocationEndpoint = 'http://localhost:9292/revoke';
ENV.ApiHost = 'http://localhost:9292';
}
return ENV;
};
You have few things to try here to debug this issue.
You could remove {{isDisabled}} from button to make sure it's not disabled when you try to click it.
Use setTimeout instead of andThen and see if it's timing issue.
Replace authenticate action code with nothing, to make sure it isn't causing your test to fail.
You could also rewrite test to put your assert.ok after some event in JavaScript. For example you could mock authenticate action or observer errors property. You can do this by using lookups or registers in acceptance environment - tests from one of my Ember CLI addons could help you - ember-link-action/tests/acceptance/link-action-test.js.
Edit
Having seen what worked for you experience tells me that you should try 2 things.
For this code:
andThen(function() {
Ember.run.later(this, function() {
assert.equal(find('div.notification').text(), "Invalid email/password");
}, 0);
});
You could try Ember.run.scheduleOnce('afterRender', this, () => { ... assert here } instead of using Ember.run.later. Or you could try using just Ember.run instead of Ember.run.later.
Conclusion: The key to fixing this issue could be putting your assertion in Ember Run Loop.
I would assume that the error you're seeing (Invalid email/password) is the (mock) server response and indicates something is wrong with either the mock or the credentials you're using in the test.
I'd also not use mirage for mocking the authentication request. mirage (just like Jason API) is resource based and not something that's well suited for authentication.
I have a simple application form which I am trying to post to the server. I am fairly new to Angular2
How can I pass the data from the component to the service and onto the server for a POST request.
The POST is working fine when I try it directly from FireFox plugin 'httpRequester'
This is the TaskComponent.ts
#Component({
selector: 'tasks',
template: `<div mdl class="mdl-grid demo-content">
<div class="demo-graphs mdl-shadow--2dp mdl-color--white mdl-cell mdl-cell--8-col">
<h3>Create Task Page</h3>
<form action="#" (ngSubmit)="onSubmit()">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" pattern="[A-Z,a-z]*" id="taskname" [(ngModel)]="data.taskname"/>
<label class="mdl-textfield__label" for="taskname">Task Name</label>
<span class="mdl-textfield__error">Only alphabet and no spaces, please!</span>
</div>
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored" type="submit">Create Task</button>
</form>
`,
directives: [ROUTER_DIRECTIVES, MDL]
})
export class CreateTaskComponent {
data: any
constructor() {
this.data = {
//taskname: 'Example Task'
};
}
onSubmit(form) {
console.log(this.data.taskname); <--Data is passed upon submit onto the console. Works fine.
//Need to call the postApartment method of ApartmentService
}
}
ApartmentService.ts
import {Http, Response} from 'angular2/http'
import {Injectable} from 'angular2/core'
import 'rxjs/add/operator/map';
#Injectable()
export class ApartmentService {
http: Http;
constructor(http: Http) {
this.http = http;
}
getEntries() {
return this.http.get('./api/apartments').map((res: Response) => res.json());
}
getProfile(userEmail :string){
return this.http.get(`./api/apartments/getprofile/${userEmail}`).map((res: Response) => res.json());
}
postApartment(){
// Not familiar with the syntax here
}
}
Server.ts
router.route('/api/apartments')
.post(function(req, res) {
var apartment = new Apartment();
apartment.name = req.body.name;
apartment.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Apartment created!' });
});
})
You can inject service via dependency injection and use it in the component
export class CreateTaskComponent {
constructor(){private _apartmentService: ApartmentService}{}
}
And you can access this in any of the component function via
onSubmit(form) {
console.log(this.data.taskname); <--Data is passed upon submit onto the console. Works fine.
//Need to call the postApartment method of ApartmentService
this._apartmentService.postApartment()
}
And when bootstraping the component you have to add it as dependency via
bootstrap(AppComponent, [ApartmentService]);
Another option for doing the last step is by added providers in the Component decorator like
#Component{
providers: [ApartmentService]
}
Inject the apartmentService in the component, No need of providers as I have bootstrapped it. (If you bootstartp the service, Do not include it in providers. It breaks the system)
export class CreateTaskComponent {
data: any
constructor(private apartmentService: ApartmentService) {
this.data = {};
}
onSubmit(form) {
this.apartmentService.postApartment(this.data);
}
}
The critical piece is the postApartment() method in the service
postApartment(data :any){
return this.http.post('/api/apartments',
JSON.stringify(data),{headers : new Headers({'Content-Type':'application/json'})
})
.map((res: Response) => res.json()).subscribe();
}
Also make sure on the server.js code, the mongoose fields match the http body parameters being passed.
I had to fix it to make it work.