Passing Parameter in Vue.js - javascript

I am trying to pass a parameter in my Vue.js project, but having no luck. The goal is when I select a user from a list, it should route to that specific user's profile as localhost:61601/Profile/"lastName"
Here is my method when I click next to the users name:
editItem(lastName) {
this.$router.push({ name: 'GetInquiry', params: { lastName: lastName } })
this.$http.get('http://localhost:61601/api/' + 'GetInquiry/' + { lastName : lastName })
},
async GetAllInquiries() {
this.loading = true
try {
this.records = await api.GetAllInquiries()
} finally {
this.loading = false
}
},
As of right now, I am just passing the lastName, but eventually, it will pass a unique id.
Here is the test Profile Page, Here I am just trying to get that users information to display to test the page. So if everything works, the users firstName should display:
<template>
<div class="Profile">
<div class="container">
<div class="row">
<template slot="items" slot-scope="records">
<h1> Student Name: {{ records.items.firstName }}</h1>
</template>
</div>
</div>
<script>
import api from '../../store/api.js'
export default {
data() {
return {
records: {},
}
},
async created() {
this.GetInquiriesByUser()
},
methods: {
async GetInquiriesByUser() {
this.loading = true
try {
this.records = await api.GetInquiriesByUser()
} finally {
this.loading = false
}
},
}
}
</script>
Here is my routes.js
{
path: '/Profile/:lastName',
name: 'GetInquiry',
component: Profile
}
When i open dev tools on chrome, I get
localhost:61601/api/GetInquiry/[object%20Object]
Im using .netcore api for the backend, which gets results as expected, just cannot seem to get it up on my frontend.
If someone can help me and point me to the right direction that would be awesome. Please do let me know if anyone needs more details.

You are passing an object on the vue-resource instead of the value.
Just pass directly the lastname into the route and it should work as fine.
this.$http.get(`http://localhost:61601/api/GetInquiry/${lastName}`);

Related

How to load locally stored images conditionally in Vuejs?

<template>
<div>
<div v-if="item">
<h1>Price: {{ item.email }}</h1>
<v-if item.email=="john#gmail.com">
<img :src="../"/>
</v-if>
</div>
</div>
</template>
<script>
import { routerid } from "./routerid";
export default {
name: "User",
components: {},
data() {
return {
item: [],
};
},
mounted() {
this.loadData();
},
computed: {
routeId() {
return this.$route.params.id;
},
},
watch: {
routeId() {
console.log("Reload (route change)");
this.loadData();
},
},
methods: {
loadData() {
console.log("Reloading, ID", this.routeId);
if (!this.routeId) return;
routerid(this.$route.params.id).then((item) => {
this.item = item.data;
});
},
},
};
</script>
How to load locally stored images conditionally in Vuejs?
I have three images stored inside of my assets folder. as below.
Now in frontend i want to call them conditionally like for example (if ---> john#gmail.com show the john image stored inside of assets folder. Else no. Similarly for other images too. Like derk and Kate...
Do i need to write if else condition. To load the images based on email? Or any other way to do that?
Code:- https://codesandbox.io/s/combined-logic-api-forked-nzzzwc?file=/src/components/User.vue
api response:- https://fakestoreapi.com/users/1
{"address":{"geolocation":{"lat":"-37.3159","long":"81.1496"},"city":"kilcoole","street":"new road","number":7682,"zipcode":"12926-3874"},"id":1,"email":"john#gmail.com","username":"johnd","password":"m38rmF$","name":{"firstname":"john","lastname":"doe"},"phone":"1-570-236-7033","__v":0}
Note:- email will be different for each id.
First. I think you should provide image link on your API Response (so you should add image link column on your database table). Or if you insist, based on your case, you can use this:
<div v-if="item">
<h1>Price: {{ item.email }}</h1>
<img :src="getPic(item.email)"/>
</div>
and in your method:
getPic(src) {
return "#/assets/" + src.substring(0, src.lastIndexOf("#")) + ".png"
}
But I still really think you should store iamge link in your database

Framework7 + Vue + Firebase: Open an individual page displaying the dynamic info from the database?

How to I get to open a user with a dynamic url each to an individual page?
I use Framework7 + Vue for a Cordova Project.
I have customized the default product page that grabs an id and display data of a single product, It works by generating the unique ID (“uid” as per firebase) for each user in a url by it fails to pass it the user.vue page that I created, it doesn’t open when I click on it. What exactly could I be missing here? I don’t know much about JSON.stringify stuffs!
user.vue - the individual data page
<f7-page name="user">
<f7-navbar :title="user.username" back-link="Back"></f7-navbar>
<f7-block-title>About {{user.username}}</f7-block-title>
<f7-block strong>
{{user.email}}
</f7-block>
</f7-page>
<script>
export default {
data: function () {
var userId = this.$f7route.params.id;
var currentUser;
this.$f7.data.users.forEach(function (user) {
if (user.user_id === userId) {
currentUser = user;
}
});
return {
user: currentUser,
};
}
};
</script>
home.vue - the user list loop, working just fine as expected
<f7-list>
<f7-list-item
v-for="(user) in users"
:key="user.user_id"
:title="user.username"
:link="`/user/${user.user_id}/`"
></f7-list-item>
</f7-list>
home.vue - mounted functions script
mounted() {
let viewUsers = this;
const usersRef = firebase.database().ref("users");
usersRef.on("value", snapshot => {
let data = snapshot.val();
let users = [];
Object.keys(data).forEach(key => {
users.push({
id: key,
username: data[key].username,
user_email: data[key].email,
user_id: data[key].uid,
});
});
viewUsers.users = users;
});
}
home.vue - data returned script at the top
data() {
return {
users: this.$f7.data.users, //the arrays had already been called/initialized at the app.vue
}
routes.js:
import UserPage from ‘…/pages/user.vue’;
{
path: ‘/user/:id/’,
component: UserPage,
}
What exactly am i missing here?

Properly rendering a task list using onSnapshot after adding/deleting items from the list

What I am making
I am making a simple task organization app using vue and firestore.
I made 5 functionalities so far.
Login
SignUp
Get and render a task list
Add / delete a task
[Not working!] Rendering any changes in list of tasks in realtime
Not working properly
It gets and loads array data from firestore and renders in realtime but, doesn't render properly
Issue detail
this issue becomes visible when it updates the list due to adding or deleting a task from the list.
Please check the image to get the clearer image of the issue.
Screenshots of issue
What I tried
Solve by refreshing the page but losing the point of having a realtime update.
Saw somewhere that set Vue () / new Vue () would solve, but did not. (Or more like I am too beginner to understand this concept to apply it...)
Most possibly I am not comprehending what's the real issue behind... So it would be great if anyone could point me out what's the real issue. So look forward to hear your ideas!
Code
There are mainly two files responsible for rendering list of tasks.
projectList.vue : where I get and load array datas and render the list of tasks
projectCard.vue : where I insert data of each tasks for projectList.vue to create the list.
(I will also add script for adding project; addProject.js just in case.)
projectList.vue : Get, load, render list of tasks
<template>
<div class="projectList">
<button class="home-buttons" #click="newProject">Add project</button>
<div v-if="createNew">
<projectAdd/>
</div>
<div v-show="loading">
<Loader/>
</div>
<div v-show="!loading">
<!--03 Pass array data to projectCard.vue then render the list of entries-->
<projectCard v-for="project in projects" :key="project.id" :project="project"/>
</div>
<p v-show="noproject">There is no project</p>
</div>
</template>
<script>
import firebase from '#/firebase/firestore';
import Loader from '#/components/loading.vue';
import projectCard from '#/components/projectCard.vue';
import projectAdd from '#/components/addProject.vue';
export default {
components: {
projectCard,
Loader,
projectAdd,
},
data() {
return {
userid: this.$route.params.userId,
//02 Put array data here
projects: [],
loading: true,
createNew: false,
};
},
created() {
//01 Get datas in realtime then pass an array data to projects: []
const db = firebase.firestore()
.collection('user')
.doc(this.userid) //$route.params.userId
.collection('projects')
.orderBy('createdAt', 'desc');
db
.onSnapshot((querySnapshot) => {
querySnapshot.forEach((doc) => {
this.projects.push(doc.data());
});
if (this.projects.length >= 0) {
this.loading = false;
} else if (this.projects.length <= 0) {
this.loading = false;
}
});
},
methods: {
newProject() {
if (this.createNew !== true) {
this.createNew = true;
} else {
this.createNew = false;
}
},
},
};
</script>
projectCard.vue : Insert each data in array
<template>
<div class="projectCard">
<div class="user-list">
<div class="columns">
<div class="column is-8">
<h3>{{ project.projectname }}</h3>
<p>{{ project.slug }}</p>
<p>Why : {{ project.why }}</p>
<p>{{ project.phase }}</p>
</div>
<div class="column is-4 right">
<router-link class="button is-primary" :to="{ name: 'viewproject', params: { projectId: project.slug }}">
Find out more!
</router-link>
<button #click="deleteProject"> Delete </button>
</div>
</div>
</div>
</div>
</template>
<script>
import firebase from '#/firebase/firestore';
export default {
name: 'ProjectCard',
props: {
// Holds array data from parent-component; projectList.vue
project: Object,
},
methods: {
// Delete a task
deleteProject() {
firebase.firestore().collection('user').doc(this.project.userId)
.collection('projects')
.where('slug', '==', this.project.slug)
.get()
.then((snapshot) => {
snapshot.forEach((doc => {
console.log(doc.data().slug);
doc.ref.delete();
alert('You have deleted the project!' + doc.data().slug);
}))
})
},
},
};
</script>
addProject.js : Add Task (this functionality is accessible from another component rendered in projectList.vue)
import firebase from '#/firebase/firestore';
export default {
addProject(createdAt, userId,projectname,why,phase){
const db = firebase.firestore().collection("user")
.doc(userId).collection("projects"); // "Project"という名前のコレクションへの参照を作成
db.add({
createdAt: createdAt,
userId: userId,
projectname: projectname,
why: why,
phase: phase,
slug: this.generateUUID(),
})
.then(function (docRef) {
console.log('Document written with ID: ', docRef.id);
alert('Well done! You have created a new project!');
})
.catch(function (error) {
console.error('Error adding document: ', error);
});
},
generateUUID() {
let d = new Date().getTime();
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
},
};
Thank you for spending your valuable time to read this far and to help me out of this issue!
Looking forward to hear some ideas from you guys!
This is because each time the listener is triggered you receive the entire result of your query, i.e. all the docs corresponding to it.
You basically have two options:
Option 1: Re-initialize your array
Re-initialize your array before populating it, as follows:
created() {
const db = firebase.firestore()
.collection('user')
.doc(this.userid) //$route.params.userId
.collection('projects')
.orderBy('createdAt', 'desc');
this.projects = []; <-- See here
db
.onSnapshot((querySnapshot) => {
querySnapshot.forEach((doc) => {
this.projects.push(doc.data());
});
if (this.projects.length >= 0) {
this.loading = false;
} else if (this.projects.length <= 0) {
this.loading = false;
}
});
},
Option 2: Listen to actual changes
As explained in the doc, you can detect "the actual changes to query results between query snapshots".
For example, you could only handle the additions, as follows:
db
.onSnapshot((querySnapshot) => {
querySnapshot.docChanges().forEach((change) => {
if (change.type === "added") {
this.projects.push(change.doc.data());
}
//....
});
//....
});

Vue - Return Promise in v-for loop

I'm having a problem with a Vue JS. I'm looping over some "posts" from the WordPress Rest API, and I have to print the author of the post inside the v-for loop, for each post. The author assigned to a post, is only an ID, so I have to make a new call to the API, to get the author name based on the returned ID.
The issue i'm running into, is that when i call the function that's fetching the Author Name, it's constantly switching back and forth between all the users assigned to the posts in the posts object.
Vue.component('blog-posts', {
props: {
posts: {},
},
data() {
return {
userName: '',
}
},
template: `
<section class="entry" v-if="posts.length">
<div class="entry-content">
<article v-for="(post, index) in posts" :key="post.index">
<h1><a :href="post.link">{{ post.title.rendered }}</a></h1>
<p v-html="post.content.rendered"></p>
// THIS IS THE PROBLEM
<p v-if="getAuthor(post.author)">{{ userName }}</p>
<button type="submit" #click="deletePost(post)">Slet indlæg</button>
</article>
</div>
</section>
`,
created() {
// Of course it works if i put a constant user id in, but i need to parse in inside the loop.
// this.getAuthor(2);
},
computed: {
},
methods: {
deletePost: function(post) {
let path = new wp.api.collections.Posts({
id: post.id
});
Event.$emit('delete-post', path, post.id);
},
getAuthor(author) {
let vm = this;
let user = new wp.api.models.User({
id: author,
});
return user.fetch().then(response => {
vm.userName = response.name;
// return true;
});
},
// showAuthor(author) {
// let user = new wp.api.models.User({
// id: author
// });
// user.fetch().then(response => {
// this.userName = response.name;
// // return true;
// });
// },
},
});
const app = new Vue({
el: '#app',
data: {
wp: wp.api,
message: 'Hello Vue',
posts: [],
},
mounted() {
let posts = new wp.api.collections.Posts();
let response = posts.fetch().then(response => {
this.posts = response;
});
Event.$on('post-added', (item) => {
this.posts.unshift(item.attributes);
});
// Delete post
Event.$on('delete-post', (item, id) => {
this.posts.forEach((post, index) => {
if ( post.id === id ) {
this.posts.splice(index, 1);
item.at(0).destroy();
}
});
});
},
});
I'm not entirely sure this is the best way to return the value of a function call.
Your issue is that your blog-posts component contains multiple blog posts, but they all share a single reference to the username. As the blog posts may be authored by different people, you will of course overwrite the username multiple times as you iterate through individual posts.
The best solution is actually to abstract individual blog post into its own atomic component, e.g., your <blog-posts> component is simply a container for multiple <blog-post>: schematically it should look like this:
└─ <blog-posts>
├─ <blog-post>
├─ <blog-post>
├─ <blog-post>
├─ <blog-post>
└─ <blog-post>
You can use :post="post" so that you pass the entire post data into your atomic component:
// The `<blog-posts>` component is only a COLLECTION of `<blog-post>`
// So it is a "dumb" component in a sense
Vue.component('blog-posts', {
props: {
posts: {},
},
template: `
<section class="entry" v-if="posts.length">
<div class="entry-content">
<blog-post v-for="(post, index) in posts" :key="post.index" :post="post" />
</div>
</section>
`
});
All post-related logic should be removed from the <blog-posts> collection component and be moved into the atomic <blog-post> component instead. Then, in your new <blog-post> component, you can:
Handle all the templating needs of an individual post
Handle individual post actions, such as post deletion
Most importantly: use the mounted() lifecycle hook to perform the API call to fetch the username pertaining to that individual post
So, your atomic component code will look a bit like this:
// The `<blog-post>` component is atomic
// It contains all the information related to a SINGLE post
Vue.component('blog-post', {
props: {
post: {},
},
data() {
// Each individual blog post stores its own username
return {
userName: '';
}
},
template: `
<article>
<h1><a :href="post.link">{{ post.title.rendered }}</a></h1>
<p v-html="post.content.rendered"></p>
<p>{{ userName }}</p>
<button type="submit" #click="deletePost(post)">Slet indlæg</button>
</article>
`,
methods: {
deletePost: function(post) {
let path = new wp.api.collections.Posts({
id: post.id
});
Event.$emit('delete-post', path, post.id);
}
},
mounted: function() {
// Fetch post author metadata when the `<blog-post>` component is mounted
let user = new wp.api.models.User({
id: author,
});
user.fetch().then(responsve => this.userName = response.name);
}
});
Everything on the display side should be reactive. You should not be calling a method, any method, in the v-if of a template. You don't know/shouldn't care when the template is rendered.
Try defining a data to hold your author details, then calling getAuthor() from a created hook.

Updating a computed property (Form) in Vue on error?

Okay so I followed along with the entire Vue Laracasts videos, which ends up having a Form and an Errors class. Here's a github link to the repo from the video:
https://github.com/laracasts/Vue-Forms/blob/master/public/js/app.js
Now what I'm trying to do is integrate Vuex to keep track of my currently logged in user, prefill a form with the current values, and show errors if any of the Laravel validation fails.
The problem I seem to be running into is that I have to set my authUser as a computed property, to pull it from the Vuex store. Then since I can't use these in anything set in data I had to move my form to a computed property. Now that it's a computed property it never gets updated so my form never has errors even when errors are being thrown.
Here's my route file Account.vue
<template>
<div>
<form #submit.prevent="onSubmit" #keydown="form.errors.clear($event.target.name)">
<div class="row">
<div class="form-group col-md-6 col-lg-3">
<label>Name</label>
<input type="text" class="form-control" name="user" autocomplete="false" v-model="form.name">
<span class="help is-danger" v-if="form.errors.has('name')" v-text="form.errors.get('name')"></span>
</div>
<div class="form-group col-md-6 col-lg-3">
<label>Email address</label>
<input type="email" class="form-control" placeholder="Enter email" autocomplete="false" name="email" v-model="form.email">
<span class="help is-danger" v-if="form.errors.has('email')" v-text="form.errors.get('email')"></span>
</div>
<div class="form-group col-lg-3">
<label>Password</label>
<input type="password" class="form-control" placeholder="Password" autocomplete="false" name="password" v-model="form.password">
<span class="help is-danger" v-if="form.errors.has('password')" v-text="form.errors.get('password')"></span>
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</template>
<script>
export default {
computed: {
authUserName: {
get: function() {
return this.$store.getters.getAuthUser.name;
},
set: function(value) {
this.$store.commit('setAuthUserValue', { key: 'name', value })
}
},
authUserEmail: {
get: function() {
return this.$store.getters.getAuthUser.email;
},
set: function(value) {
this.$store.commit('setAuthUserValue', { key: 'email', value })
}
},
form() {
return new Form({
name: this.authUserName,
email: this.authUserEmail,
password: ''
})
}
},
data() {
return {
}
},
mounted() {
},
methods: {
onSubmit() {
this.form
.patch('/current-user')
.then(status => {
this.$emit('success', status);
});
}
}
}
</script>
index.js
import AuthUser from "../models/AuthUser";
export default new Vuex.Store({
state: { // = data
authUser: {
name: null,
email: null,
}
},
getters: { // = computed properties
getAuthUser(state, getters) {
return state.authUser;
}
},
actions: { // = methods
fetchAuthUser(context) {
AuthUser.load(user => {
context.commit('setAuthUser', user);
});
}
},
mutations: {
setAuthUser(state, user) {
Vue.set(state, 'authUser', user);
},
setAuthUserValue(state, payload) {
state.authUser = { ...state.authUser, payload }
}
}
});
app.js
import router from './routes';
import Hamburger from './components/Hamburger';
import NavHeader from './components/NavHeader';
import store from "./store/index";
new Vue({
el: '#app',
components: {
Hamburger,
NavHeader
},
data() {
return {
}
},
created() {
store.dispatch('fetchAuthUser');
},
router,
store
});
I've tried messing around with watchers, but everything threw errors. I'm trying really hard to get the form to be created with the existing users values preset, and was recommended to try vuex, but am now running into these issues where form now needs to be computed instead of set in data, so form never has errors now. Sorry, pulling my hair out learning all these new things at once lol.
EDIT
I've now also tried setting form to an empty form object in data, then setting the properties in mounted(), but no matter how I try to access authUser in mounted I'm getting undefined.
mounted() {
console.log(this.authUser);
console.log(this.authUser.name);
console.log(this.$store.getters.getUser.name);
},
outputs...
{ob: Observer}
undefined
undefined
EDIT 2
Latest code updated, still not getting the errors to show up below the input, although they do show up under the dev tools in..
Root > Account > computed > form > errors > errors
In there it lists name and email errors if I left them blank. Could it be cause it's double nested? I know this is a Laravel issue with how it nests the json response.
Perhaps something in that Form or Errors class in app.js?
AuthUser.load is an asynchronous function, as you're executing it in the created hook, it's not guaranteed that authUsers values will be set by the time that the Account.vue's created hook is fired.
Now the issue that you're having is due to the fact that you have a computed property with no setter. The Form class attempts to mutate the value of the store directly, which will result in the console exploding.
If you provide a setter for your value, when you attempt to write to it, you can react to the value being passed to the setter and you can dispatch (or in your case, commit) that value to the store:
computed: {
authUser: {
get(): {
return this.$store.getters.getUser;
},
set(value): {
this.$store.commit('setUser', value)
}
}
}
But wait, this still won't work! Why? Because the value you will receive will just be the text input value, how will you know which property within the AuthUser to update? Probably the easiest way to resolve that is to create a computed property for each property on the authUser
computed: {
authUserName: {
get(): {
return store.getters.getUser.name;
},
set(value): {
this.$store.commit('setUser', { key: 'name', value })
}
},
authUserEmail: {
get(): {
return store.getters.getUser.email;
},
set(value): {
this.$store.commit('setUser', { key: 'email', value })
}
},
authUserPassword: {
get(): {
return store.getters.getUser.password;
},
set(value): {
this.$store.commit('setUser', { key: 'password', value })
}
}
}
Now you can instantiate the form with each of the getters:
new Form({
name: this.authUserName,
email: this.authUserEmail,
password: this.authUserPassword
})
But, yet again, this still won't work! We need a new mutation that will only write properties of our authUser
setUserValue(state, payload) {
state.authUser = { ...state.authUser, payload }
}
By using a simple destructure we can overwrite the properties of our authUser and merge in the new value of the computed property.
Now you need to update your computed properties and use this.$store.commit('setUserValue', { key: 'name/email/password': value}) in your setter instead.
Finally, your authUser should be an object with preset properties:
authUser: {
name: null,
email: null,
password: null
}
This is important as properties of an object are reactive. However, if properties are added to the object, you cannot simply overwrite the object and have new reactive properties. You would need to use Vue.set() for this, such as:
setUser(state, user) {
Vue.set(state, 'authUser', user)
}
This would correctly allow for the observed properties to become reactive. This is an important concept in the reactivness of the VueX store. This is also the reason why your values are undefined.

Categories