I am trying to slice an array of items in Vue
here is my code
<template>
<div v-for="item in Items" :item="item" :key="item.id">{{ item.name }}</div>
</template>
<page-query>
query {
count
items {
id
name
}
}
</page-query>
<script>
export default {
props: {
items: Array,
}
computed: {
Items() {
return this.items.slice(0, 4);
},
}
}
</script>
As you can see I am slicing the array by 4.
In my API data I have a "count" object that returns a number I need to use to slice the items but I cant figure out a way how. Could you please give me a hint how to use count data instead of hardcoded number 4?
Using limit should help you
<page-query>
query {
count
items(limit: 4) {
id
name
}
}
</page-query>
Related
I want to print the data in the inputs in the image to the screen via node js, how can I do this?
You could use a combination of an Array and an v-for statement
Basically:
//The UI
<ul>
<li v-for="(item, key) in array" v-bind:key="key">
//Here you can use now every item in the Array like this for example
<span>{{ item.name }}</span>
</li>
</ul>
//The code
export default {
data() {
return { array: [] };
},
methods: {
apiDataFunction() {
axios
.post('xxx') //Or whatever you have
.then((res) => {
this.array.push(res.data);
});
}
}
};
If you could give some more information I could help more.
For example, how the data looks that you retrieve with axios etc.
I didn't test this code personally so it may be, that you would need to pack this array into an computed statement
From the Vue documentation:
The prop is passed in as a raw value that needs to be transformed. In
this case, it’s best to define a computed property using the prop’s
value.
Source
What if this "prop" is array of the objects? I tried to transform it to computed array according documentation. But how to mutate in then?
In below example, component accepts array of items Array<{ ID: string, lettering: string; }>.
Component renders buttons for each item.
When we click the button, it must change the color.
If we click same button again, it must return to initial state.
Fiddle
<template>
<div>
<button
v-for="(item, index) in selectableItems"
:key="`BUTTON-${item.ID}`"
:class="{ selected: item.selected }"
#click="() => {onButtonClicked(item, index) }"
> {{ item.lettering }}
</button>
</div>
</template>
I compute the selectableItems from items. selectableItems has property selected in addition to item's properties.
export default {
name: "HelloWorld",
props: {
items: Array
},
computed: {
selectableItems: function () {
const selectableItems = [];
this.items.forEach((item) => {
selectableItems.push({
ID: item.ID,
lettering: item.lettering,
selected: false
});
});
return selectableItems;
}
},
methods: {
onButtonClicked: function(item, index) {
if (item.selected) {
this.selectableItems[index].selected = false;
} else {
this.selectableItems[index].selected = true;
}
console.log(this.selectableItems);
}
}
};
Currently, Vue dues not re-render buttons.
I know that the mutate the getter is improper usage.
But how I should to mutate the array?
Forbidden solution
Passing the { ID: string, lettering: string; selected: boolean; } via props instead of { ID: string, lettering: string; } is not allowed. { ID: string, lettering: string; } is pure model, and it must not know about UI. selected: boolean; is for UI only.
Here's a quick example in a jsfiddle https://jsfiddle.net/hgvajn5t/
As I'm short on time I've skipped creating two components and actually reach down the data as props.
Key is to define your selected buttons in your data
data () {
return {
selectedItems: []
}
},
Second part is to store which items are selected and which aren't
onButtonClicked: function(item){
let index = this.selectedItems.indexOf(item.ID)
if (index > -1) {
this.selectedItems.splice(index, 1)
} else {
this.selectedItems.push(item.ID)
}
}
The onButtonClicked recives the item as input and checks if it exists in your selectedItems - if so it will be removed, otherwise it will be added
Final part is to change your binding to set the selected class
:class="{ selected: selectedItems.indexOf(item.ID) > -1 }"
Here again - simply check if it is part of the selectItems
You can then remove your computed property and simply use the props to loop through the elements.
IMPORTANT: This will only work if your item ID values are unique.
Some general thoughts on this: The concept of this can be a bit hard to wrap your head around when you're new to vue, as it seems to be very complicated for simple select states. This might be true for the solution I gave - but overall it highly depends on how you structure your UI in general. The main reason for all this is that you should not manipulate props directly. Using computed props to enhance them is good - manipulating computed props is just as bad. If you need the select state outside your current component you will need to think about using events to emit the click on a button to the parent (where the data comes from) and change the select state directly there. It will then be passed down via props directly. This is the more "natural" way as you manipulate the single source of truth instead of holding additional information about the items in another screen.
I need to put out a list of users based on whether they are active or not. I know I can separate the v-for and the v-if in nested divs but I can't because of the construct of the html. Also I need this for pagination purposes.
So I have my API containing thousands of users (some active true and same active false)
My template looks like this for the active ones:
<div v-if="filterformData.filterby === 'Active Operators'">
<div v-for="(user, key) in operators" :key="key" v-if="user.active">
User Name: {{user.name}}
User ID: {{user.id}}
...
</div>
</div>
Note: the first v-if it's checking for a dropdown select option of name Active Operators. That's in my data object.
My script relevant lines look like this
computed: {
...mapGetters("users", ["operators"])
},
methods: {
...mapActions("users", ["getUsers"])
}
created() {
this.getUsers();
}
My store relevant lines look like this:
import { axiosInstance } from "boot/axios";
export default {
namespaced: true,
state: {
operators: []
},
getters: {
operators: state => {
return state.operators;
}
},
actions: {
async getUsers({ commit }) {
const response = await axiosInstance.get("operator");
commit("setUsers", response.data.data);
}
},
mutations: {
setUsers: (state, operators) => (state.operators = operators)
}
};
Again, I'd like to contain the active users in a computed property that I can use for the loop. And eventually, I will be making another one for inactive users as well
Thanks
Just filter the active users in a computed property like this
computed: {
...
activeUsers() {
return this.operators.filter(user => user.active)
}
},
and change the v-for directive to this
<div v-for="(user, key) in activeUsers" :key="key">
and it should work without v-for and v-if on the same element.
I have a Vue list that is based of an array and each array item renders a component where I bind the array item properties.
<div v-for="item in items">
<item v-bind:item="item"></item>
</div>
This component has a mixed data, based on the binded properties
Vue.component('item', {
template: '<p>ID: {{item.id}}, {{component_id}}</p>',
props: ['item'],
data: function() {
return {
component_id: this.item.id
}
}
});
The problem is that when I change the initial list array in any way, the mixed prop of the component maintains it's original update and does not change, even if the original binded data changes.
http://codepen.io/anything/pen/bgQBwQ
How can I make the component to update it's ow data property?
As requested in the form of an answer:
In this case a computed property is the correct approach, leading to the following code:
Vue.component('item', {
template: '<p>Original: {{item.id}}, Mixed: {{component_id}}, Computed: {{computed_id}}</p>',
props: ['item'],
computed: {
computed_id: function() {
return this.item.id;
}
}
});
This way the computed_id will be (correctly) recomputed every time the item prop changes.
I am learning React-Redux and I have an issue navigating through the objects in my JSON file. I have the following file JSON, the file is designed to render out a side navigation:
export default function(){
return [
{
catId:"parMenu1",
parentCat:"Genres",
subcat:[
{
genre:"8Bit",
genreId:"1"
},
{
genre:"Acid House",
genreId:"2"
}
]
},
{
catId:"parMenu2",
parentCat:"sounds",
subcat:[
{
genre:"blah",
genreId:"3"
},
{
genre:"blah House",
genreId:"4"
}
]
]
}
I have the JSON file mapped to state props for a component. The component looks like so:
class BrowseByCont extends Component {
render () {
return (
<div className="browseByContInner">
{
console.log(this.props.reducerSidenav[0].catId)
}
</div>
)
}
}
function mapStateToProps(state) {
return {
reducerSidenav:state.reducerSidenav
};
}
I am trying to reach the subcats object within the parent object. The JSON object is linked to a variable called "reducerSidenav". So far I have managed to get this far into my JSON file: this.props.reducerSidenav[0].catId. this spits out the value parMenu1 which is the "parent" object I want to target. Where I am stuck though is I am trying to achieve two things:
firstly - I would like to access the first "parent" object by without having to refer to the first item in the array: reducerSidenav[0] but rather by find the catId with a value of parMenu1. This is because this list will be dynamic in future and referring to the first array object is not reliable.
secondy - I would then like to access the subcat object and get to the value thats associated to the key genre ie to return the value "8Bit"
You can use .find() to achieve both things.
class BrowseByCont extends React.Component {
render () {
let first = this.props.reducerSidenav.find(item => item.catId === "parMenu1");
let second = first.subcat.find(subcat => subcat.genre === "8Bit")
return (
<div className="browseByContInner">
<div>{first.catId}</div>
<div>{second.genre}</div>
</div>
)
}
}
Edit
In order to print all the subcats, you have to use .map()
class BrowseByCont extends React.Component {
render () {
let first = this.props.reducerSidenav.find(item => item.catId === "parMenu1");
return (
<div className="browseByContInner">
{first.subcat.map(genreItem =>
<div key={genreItem.genreId}>{genreItem.genre}</div>)
}
</div>
)
}
}
jsfiddle