Bind data to component with Vuex - javascript

I'm new to vue.js and I'm trying to use vuex. Here is my issue:
I have a list of articles (which is a component) linked with a store with v-for="article in articles and a computed property:
computed: {
articles() {
return this.$store.state.articles
}
}
So here is the data in my store:
state: {
articles: [{
title: "Article 1",
id: 1,
description: "Article 1",
}, {
title: "Article 2",
id: 2,
description: "Article 2",
}
}]
}
When I click on an article, I want it to redirect to the article page template (which is a component) with <router-link :to="{path: '/article/'+article.id}"></router-link>.
What I'm trying to do is bind the data of the correct article in the articlePage template.
The issue is that if I apply the same computed property to my articlePage.vue component with a v-for, I will display all of the article on the same page. I would like to display only the matching id component.
How can I do that?
Thank you for your time :)

From your comments I understand that you use vue-router module
So in your routes.js (or structure ) your must have something like this
const router = new VueRouter({
routes: [
{ path: '/articles', component: articlesPage },
{ path: '/article/:id', component: articlePage }
]
})
Then in your articlePage component you can extract ":id" like this:
this.$route.params.id
because vue-router gives you access to the object $route with methods and properties
Check more here https://router.vuejs.org/guide/essentials/dynamic-matching.html
then you can use it to search the articles array and find the data and present them
e.x.
computed:{
selectedArticle(){
var article_id = this.$route.params.id;
var articles = this.$store.state.articles;
var article = null;
for(var a=0;a<articles.length;a++){
if(articles[a].id == article_id ){
article = articles[a];
break;
}
}
return article;
}
}

Related

How to pass input value data from Vue component to root element

I want to post json data from Vue to php, but I'm struggling to find a way to pass input value data from Vue component to root element.
When I call method submitProduct, alert message simply gives me 'undefined'.
I had to strip my original code because of that stupid post balance policy.
What's wrong here?
var productForm = Vue.createApp ({
methods:{
submitProduct: function(){
alert(JSON.stringify(productForm.product))
this.postData(productForm.product)
},
postData: function(p){
fetch('mysql_postdata.php', {
method: 'POST',
mode: "same-origin",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({p:p})
//body: 'd='+d
})
}
}
})
productForm.component('custom-form', {
props: ["value"],
template: `
<label>SKU<input type="text" :value=this.product.sku></label>
<label>Name<input type="text" :value=this.product.name></label>
<label>Price<input type="text" :value=this.product.price></label>
` ,
data: function() {
return {
product: {
sku: 0,
name: 'asdf',
price: 0
},
options: ['Size', 'Weight', 'Dimensions'],
selected: 'Size'
}
}
})
productForm.component('status-bar', {
props: ['info'],
template: '<p>{{ selected }}</p>'
})
const vm = productForm.mount('#product_form')
The product state belongs to the custom-form component so the root app cannot access the state.
If you trying to create a form and get the input from the form, you need to do 1 of this:
Lift the state to the root and pass down the custom-form and bind an event to listen to the state change docs here. (only do this if the custom-form component is not deep down in the component tree)
Using the state management store like Vuex to share the state within the app (in case the child component is deep down in the tree you have to pass the state down so many levels, using store management will solve that). docs here. If your app is really small consider the provide/inject API.
Another choice is using the provide/inject API (similar to the context provider in react).
First of all after 3.5 days of struggling to try to understand Vue I came with tested successfull result. I want to thank you and anybody else, who helped me to understand basics principles in Vue! :)
Please see link below...
https://jsfiddle.net/e2mnh4xa/
P.S. And yes! You are right about rearranging 'custom-form' tag. :)
html code:
<div id="product_form" v-cloak>
<custom-form>
</custom-form>
</div>
js code:
var productForm = Vue.createApp ({})
productForm.component('custom-form', {
props: {
modelValue: {
type: String,
default: ''
},
},
components: ['status-bar'],
template: `
<button v-on:click="submitProduct">Save</button>
<label>SKU<input type="text" v-model="this.product.sku"></label>
<label>Name<input type="text" v-model="this.product.name"></label>
<label>Price<input type="text" v-model="this.product.price"></label>
` ,
data: function() {
return {
product: {
sku: 0,
name: 'asdf',
price: 0,
},
options: ['Size', 'Weight', 'Dimensions'],
selected: 'Size',
outputData: ''
}
},
computed:{
model:{
get(){ return this.modelValue },
set(v){ this.$emit('update:modelValue',v)}
}
},
methods:{
submitProduct: function(){
alert (this.showData());
return this.postData(this.product)
},
showData: function(){
console.log(this.product.sku)
return JSON.stringify(this.product)
}
}
})
const vm = productForm.mount('#product_form')

Update deeply nested react redux state array element

I have a redux state array like this
[{
client_id:12,
template:{
item1:[],
item2:[],
simple templates:[
"Some paragraph 1",
"Some paragraph 2",
"Some paragraph 3",
]
}
}]
So I want to update an element on the simple templates array using redux immutability helpers https://reactjs.org/docs/update.html. For example I want to update "Some paragraph 2" with "Some paragraph #2". I'm passing the data I want to update using a form to the reducers.
So far I have been trying something like this
case TEMP_UPDATE_TEMPLATE: {
console.log('index', action.payload.index);
console.log('data', action.payload.data); //new data that I want to update
return update(state.simple_templates, {
[0]: {
template: {
"Simple Templates": {
[action.payload.index] : {
$set: action.payload.data
}
}
}
}
})
}
It's really confusing for me. Please help me to understand how to update an element of deeply nested object array with a given index.
Try to use $splice instead of $set as it is an array.
return update(state.simple_templates, {
[0]: {
template: {
"simple templates": {
$splice: [action.payload.index, 1, action.payload.data]
}
}
}
})

Vuejs passing arguments with a routes href link

I'm quite new to Vuejs, so Sorry in advance!
I have a component called "Goods" which shows all the items in a route path ("/Goods") and another component called "AddGoods" at ("/AddGoods") which is a form and submits data to my database table.
I have to use two separate pages for these two and they work closely together.
now I also want to be able to use my AddGoods form for editing and showing details on my already added Goods and I'm having trouble finding a way to send some parameter with the link so that I could manage my field and buttons based on each situation (like making fields readonly for showing details and so on).
here's my route.js :
{
path: "/addGoods",
name: "add goods",
meta: {
title: "Add Goods",
},
component: () => import("../views/GoodsManagment/AddGoods.vue"),
},
{
path: "/goodsTbl",
name: "goods tbl",
meta: {
title: "Goods Table",
},
component: () => import("../views/GoodsManagment/GoodsTbl.vue"),
},
and here's the link to "AddGoods" :
<v-btn v-on="click" href="/AddGoods"> Add a new item </v-btn>
So I ended up doing it like this :
route.js:
{
path: "/addGoods/:id",
name: "add goods",
meta: {
title: "Add Goods",
},
component: () => import("../views/GoodsManagment/AddGoods.vue"),
},
{
path: "/goodsTbl",
name: "goods tbl",
meta: {
title: "Goods Table",
},
component: () => import("../views/GoodsManagment/GoodsTbl.vue"),
},
and to call it , I personally found the Programmatic Navigation easier to use, so :
this.$router.push({name: "add goods", params: { id: 123 }});

How to Structure Normalized Redux Store When Loading Data

I am trying to create a React/Redux app which lists books. Each book then has related books. I know I should structure my redux store in some sort of normalized fashion like so:
{
books: {
'book1id': {
title: 'Book 1',
author: 'Author 1',
relatedBooks: ['book2id', 'book3id']
},
'book2id': {
title: 'Book 2',
author: 'Author 2',
relatedBooks: ['book1id']
}
}
}
and load each book as necessary.
The issue is where to store loading/error data from the API requests? Some ideas I had were to create an object for every book such as
books: {
'book1id': {
isLoading: false,
error: null,
book: {
title: 'Book 1',
...
}
},
...
}
But that seems to detract slightly from the readability/intuitiveness of the state. Is there a better way to structure the state?
I structure my redux store so that it includes an entities object for all of my relational data and I store things specific to a page or a set of routes in separate parts of the state. My state tree might look something like this:
const state = {
entities: {
books: {
...
},
authors: {
...
},
...
},
booksPage: {
isLoading: false
}
}
Now I am keeping track of my relational state separate from the state of my UI components. I would not recommend trying to store a isLoading state in an individual entity since that entity may or may not exist. If you need more granular loading/error state on a per entity basis then rather on a set of entities you have a few options. The first option is keep a set of IDs that are currently loading. This is not a very practical solution because you can't track success or failure with an ID simply being in a set or not.
The next, better solution is to keep a map from ID to a status object that includes if an individual entity is loading, if it was successful or if it failed to load and what the errors were.
const state = {
entities: {
books: {
...
},
authors: {
...
},
...
},
booksPage: {
loading: {
book1: {
status: 'FAILED',
error: 'Network request failed.'
},
book2: {
status: 'SUCCESS',
},
book3: {,
status: 'IN_PROGRESS'
}
}
}
}
In summary, I find separating out your relational state into an entities child object while having page specific sections of state to be working quite well for me.

Objects in Ember Data

This has been asked a couple times, but the examples didn't help a whole lot.
I want to post 'posts' to my server, so I have a 'posts' model and then a 'single' model. The 'posts' model represents all the posts, and then my 'single' model represents what each post needs... I am new to Ember.js, and really could use a hand here/direction.
So when I submit the form (for creating a new post):
// When the form is submitted, post it!
actions: {
// createNew begin
createNew() {
var title = this.controller.get('title');
var content = this.controller.get('content');
const data = {
"posts": [
{
"title": title,
"content": content
}
]
};
return this.store.createRecord('posts', data).save().
then(function(post) {
console.log(post);
}, function(error) {
console.log(error);
});
} // end of createNew
}
'posts' model:
import DS from 'ember-data';
export default DS.Model.extend({
posts: DS.hasMany('single'),
});
'single' model:
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
content: DS.attr('string'),
});
And then my serializer to hook the two together...
import DS from 'ember-data';
export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
posts: { embedded: 'always' }
}
});
Currently, this is the error that outputs:
"Assertion Failed: All elements of a hasMany relationship must be instances of DS.Model, you passed [[object Object]]"
In Short: I need to create data models that can represent the following JSON structure:
{
"posts": [
{ "title": "Title", "content": "Content" }
]
}
Thanks!
The error is actually saying exactly what's wrong.
"Assertion Failed: All elements of a hasMany relationship must be instances of DS.Model, you passed [[object Object]]"
The model posts has a hasMany relationship to the model single.
What your code is doing is passing a plain JS object instead of the model.
const data = {
"posts": [
{ // <-
"title": title, // <-
"content": content // <- this is a POJO
} // <-
]
};
One way to solve this actually is to create the two objects separately.
// create 'posts' and 'single' separately
const posts = this.store.createRecord('posts');
const single = this.store.createRecord('single', {
title,
content
});
// link them up
posts.get('posts').addObject(single);

Categories