Populate table in Vue template component from rest api - vue-component

I have a Vue component where I am trying to get rest api (using axios) data to populate a table. The rest call returns a valid json string in chrome. However, I can't get it to populate the table in the template. When I run the view, I get the following error in the rest call:
TypeError: Cannot set property 'courses' of undefined
Here is the json being returned:
[{"CourseId":"architecture","AuthorId":"cory-house","Title":"Architecting
Applications","CourseLength":"4:20","Category":"Software Architecture
Test"}]
Here is my template:
<template>
<div class="course-list-row">
<tr v-for="course in courses">
<td>{{ course.CourseId }}</td>
<td>{{ course.AuthorId }}</td>
<td>{{ course.Title }}</td>
<td>{{ course.CourseLength }}</td>
<td>{{ course.Category }}</td>
</tr>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'course-list-row',
mounted: function () {
this.getCourses()
console.log('mounted: got here')
},
data: function () {
return {
message: 'Course List Row',
courses: []
}
},
methods: {
getCourses: function () {
const url = 'https://server/CoursesWebApi/api/courses/'
axios.get(url, {
dataType: 'json',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
mode: 'no-cors',
credentials: 'include'
})
.then(function (response) {
console.log(JSON.stringify(response.data))
this.courses = JSON.stringify(response.data)
})
.catch(function (error) {
console.log(error)
})
}
}
}
</script>
Edit:
It appears the "this" of this.courses in the api callback function is undefined.

as you have edited, you have got the correct error, scope of this has changed inside axios.get, you need to make following changes:
methods: {
getCourses: function () {
var self = this
const url = 'https://server/CoursesWebApi/api/courses/'
axios.get(url, {
dataType: 'json',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
mode: 'no-cors',
credentials: 'include'
})
.then(function (response) {
console.log(JSON.stringify(response.data))
self.courses = response.data
})
.catch(function (error) {
console.log(error)
})
}
}

Related

How can I update state immediately inside a submit handler?

i'm trying to run 3 fetch requests to an API in an submit handler in React, and use the data that is returned from the first two fetch request in a third fetch within the same submit event. The problem i'm running into is that the State is not immediately updating from the first two fetch requests, and when it comes to the third, the state that is coming into "dbtask" for category_id and user_id, comes in as undefined. Outside the body of the handler function the state shows correctly, How can I change this so that the state will proprerly update "dbtask"?
function submitHandler(e){
e.preventDefault()
const [fname, lname] = submission.name.split(' ');
const fullname = {
first_name: `${fname}`,
last_name: `${lname}`,
}
const dbcategory = {
category_name: submission.category
}
//Post method for users
fetch("http://localhost:9292/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(fullname),
})
.then((r) => r.json())
.then((newUser) => {
setNewUser({newUser}, () => {
console.log(newUser)
});
})
console.log(newUser)
// Post method for categories
fetch("http://localhost:9292/categories", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(dbcategory),
})
.then((r) => r.json())
.then((newCategory) => {
setNewCategory({newCategory}, () => {
console.log(newCategory)
});
})
console.log(newCategory)
const dbtask = {
task_name: submission.task,
category_id: newCategory.id,
user_id: newUser.id
}
console.log(dbtask)
fetch("http://localhost:9292/tasks", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(dbtask),
})
.then((r) => r.json())
.then((newTask) => {
setNewTask(newTask)
})
console.log(newTask)
setTasks(tasks => [...tasks, newTask])
}

Why my async fetch doesn't work client side?

I'm having an issue to get my component working client side with fetch (it's ok when I'm refreshing the page) in Nuxt.
The $fetchState.error doesn't load any error though. But my console.log in my mounted hook doesn't load any data.
I don't know what I'm doing wrong here. I'm using target: 'static'
<template>
<p v-if="$fetchState.pending">Fetching realisation...</p>
<p v-else-if="$fetchState.error">An error occurred :(</p>
<nuxt-link v-else :to="real.full_slug" class="real">
<div class="real__content">
<h2>{{ real.name }}</h2>
</div>
</nuxt-link>
</template>
<script>
export default {
props: {
realisation: {
type: Object,
required: true
}
},
data() {
return {
real: {}
}
},
async fetch() {
this.real = await this.$storyapi
.get(`cdn/stories/${this.realisation.work}`, {
version: 'published',
find_by: 'uuid'
})
.then((res) => {
return res.data.story
})
.catch((err) => console.log(err))
},
mounted() {
console.log(this.real)
},
fetchOnServer: true
}
</script>

Vue Vuex Firebase Auth email sign in and update username

I've got firebase auth setup, however, I'm trying to update username before setting that to my current state. When I run everything before the update, everything works fine, but I dont have a username. I'm fairly new with js promises so I've tried running the function and returning the function, neither have really worked. My expectation is that by the time the dashboard screen shows, that the username is set.
Below is the code for signup via email which works without username.
store/user/index.js
signUserUp ({commit}, payload) {
commit('setLoading', true)
commit('clearError')
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(function (user) {
return user.updateProfile({
displayName: payload.username
})
})
.then(
profile => {
commit('setLoading', false)
const newUser = {
id: profile.uid,
name: profile.username,
email: profile.email,
photoUrl: profile.photoURL
}
commit('setUser', newUser)
}
)
.catch(
error => {
commit('setLoading', false)
commit('setError', error)
console.log(error)
}
)
}
This is the code that returns an error and does not update the username until I refresh.
signUserUp ({commit}, payload) {
commit('setLoading', true)
commit('clearError')
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(function (user) {
return user.updateProfile({
displayName: payload.username
})
.then(
profile => {
commit('setLoading', false)
const newUser = {
id: profile.uid,
name: payload.username,
email: profile.email,
photoUrl: profile.photoURL
}
commit('setUser', newUser)
}
)
.catch(
error => {
commit('setLoading', false)
commit('setError', error)
console.log(error)
}
)
},
My view is really simple just displaying the data.
<template>
<div>
<h1>Dashboard</h1>
<button #click="onLogout">Logout</button>
<hr>
<app-alert v-if="error" #dismissed="onDismissed" :text="error.message"></app-alert>
<img :if="user.photoURL" :src="user.photoUrl">
<h4><b>Display Name :</b> {{ user.name }}</h4>
<h4><b>Email :</b> {{ user.email }}</h4>
<h4><b>Email Verified :</b> {{ user.emailVerified }}</h4>
<h4><b>User ID :</b> {{ user.id }}</h4>
</div>
</template>
<script>
export default {
date () {
return {}
},
computed: {
user () {
return this.$store.getters.user
},
error () {
return this.$store.getters.error
}
},
methods: {
onLogout () {
this.$store.dispatch('logout')
this.$router.push('/')
},
onDismissed () {
this.$store.dispatch('clearError')
}
}
}
</script>
The errors I get back are an alert that states
Cannot read property 'uid' of undefined
And also, username does not display on the page component, even though it does display on page refresh.
Everything works fine up until I add this bit to try and update the username on user create, so this little bit doesn't pass the new updated user object.
.then(function (user) {
return user.updateProfile({
displayName: payload.username
})
})
Looks like my problem was in how I was sequencing my functions, in place of returning the user.updateProfile function, I was able to nest my updateProfile call like below, additionally, I was calling username as the object username when it should've been displayName.
signUserUp ({commit}, payload) {
commit('setLoading', true)
commit('clearError')
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(function (user) {
user.updateProfile({
displayName: payload.username
}).then(
() => {
commit('setLoading', false)
const newUser = {
id: user.uid,
name: user.displayName,
email: user.email,
emailVerified: user.emailVerified
}
commit('setUser', newUser)
}
).catch(
error => {
commit('setLoading', false)
commit('setError', error)
console.log(error)
}
)
})
.catch(
error => {
commit('setLoading', false)
commit('setError', error)
console.log(error)
}
)
},

WordPress REST API not working when filtering by slug using Axios

I was able to display WordPress post content using axios and Vue.js. Once I switched to filtering by slug, I was unable to display post content.
<template>
<div>
<article>
<h2 class="subtitle">{{ post.title.rendered }}</h2>
<div v-html="post.excerpt.rendered"></div>
</article>
</div>
</template>
<script>
import axios from "axios";
import Router from 'vue-router'
export default {
name: 'ShowPost',
data () {
return {
post: []
}
},
created() {
this.slug = this.$route.params.slug;
},
mounted() {
axios({ method: "GET", "url": "https://wpdemo.stevensoehl.com/wp-json/wp/v2/posts?slug=" + this.slug }).then(json => {
this.post = json.data;
}, error => {
console.error(error);
});
}
}
</script>
It is necessary to check whether there is cross domain problem in the console, and there may be no cross domain problem
I figured it out a solution. In my links to an individual post I carried over the slug and id as params
<router-link :to="{name: 'ShowPost', params: {slug: post.slug, id:post.id}}">{{ post.title.rendered }}</router-link>
Route is slug and filter response by id. It now works as planned.
import axios from "axios";
export default {
name: 'ShowPost',
data () {
return {
post: []
}
},
created() {
this.id = this.$route.params.id;
},
mounted() {
axios({ method: "GET", "url": "https://wpdemo.stevensoehl.com/wp-json/wp/v2/posts/" + this.id }).then(json => {
this.post = json.data;
}, error => {
console.error(error);
});
}
}

How to test cyclejs http driver?

Suppose I have an API that return user detail:
/api/get_user/1
{
"status": 200,
"data": {
"username": "username1",
"email": "username#email.com"
}
}
And a "main function" like this:
function main (sources) {
const request$ = sources.ACTIONS
.filter(action => action.type === 'GET_USER_REQUEST')
.map(action => action.payload)
.map(payload => ({
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}))
const action$ = sources.HTTP
.select('GET_USER_REQUEST')
.flatten()
.map(response => response.data)
const sinks = {
HTTP: request$,
LOG: action$
}
return sinks
}
For testing the "ACTION" source, I can simply made an xstream observable
test.cb('Test main function', t => {
const actionStream$ = xs.of({
type: 'GET_USER_REQUEST',
payload: { userId: 1 }
})
const sources = { ACTION: actionStream$ }
const expectedResult = {
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}
main(sources).HTTP.addEventListener({
next: (data) => {
t.deepEqual(data, expectedResult)
},
error: (error) => {
t.fail(error)
},
complete: () => {
t.end()
}
})
})
The question is. Is it possible to do the same thing (using plan xstream observable)
to test cycle-http driver without a helper from something like nock?
Or is there a better way to test something like this?
You can mock out the HTTP source like so:
test.cb('Test main function', t => {
const actionStream$ = xs.of({
type: 'GET_USER_REQUEST',
payload: { userId: 1 }
})
const response$ = xs.of({
data: {
status: 200,
data: {
username: "username1",
email: "username#email.com"
}
}
});
const HTTP = {
select (category) {
// if you have multiple categories you could return different streams depending on the category
return xs.of(response$);
}
}
const sources = { ACTION: actionStream$, HTTP }
const expectedResult = {
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}
main(sources).HTTP.addEventListener({
next: (data) => {
t.deepEqual(data, expectedResult)
},
error: (error) => {
t.fail(error)
},
complete: () => {
t.end()
}
})
})
Really, we should have a mockHTTPSource helper to make this a bit easier. I have opened an issue to that effect. https://github.com/cyclejs/cyclejs/issues/567
If you want to test that certain things happen at the correct time, you could use this pattern in conjunction with #cycle/time.
http://github.com/cyclejs/time

Resources