I want to generate dynamic data field using value of prop passed in child component.
Code:
...
<datafieldcheckbox :categories="abc" #call-method="callfilteredproducts"></datafieldcheckbox>
new Vue({
el: "#app",
data: {
abc: null, // this will generate based on a value of prop passed in child component.
products: [
{
"id": "1",
"name": "Product1",
"abc": "EEE",
"skill": "Easy",
"color": "blue",
"price": 100.00
},
{
"id": 2,
"name": "Product2",
"abc": "EEE",
"skill": "Intermediate",
"color": "red",
"price": 120.00
},
{
"id": 3,
"name": "Product3",
"abc": "Office",
"skill": "Intermediate",
"color": "green",
"price": 190.00
}
]
...
const dfCheckBox = Vue.component('datafieldcheckbox', {
template: `<div id="one">
<h4><strong>Categories</strong></h4>
<ul class="categoriesFilter">
<li v-for="category in categories"><label><input type="checkbox" :id="category" :value="category" v-model="selectedFilters.categories" #click="filterProducts()"><span class="categoryName">{{category}}</span></label></li>
</ul>
</div>`,
data() {
return{
products : null,
selectedFilters: {
categories: [],
colors: [],
minPrice: null,
maxPrice: null
}
}
},
props : ['categories'],
methods: {
filterProducts(){
this.$emit('call-method', this.selectedFilters);
}
}
});
like in above code If I write abc then it will generate this kinda code in parent data:
Now let's say I have data in products and I want to find unique values of a key that is passed from child props.
Just pass the product array to child component and filter the category by checkbox. pls try this
template
<!-- child -->
<script type="text/x-template" id="grid-template">
<div>
<h2>
category list:
</h2>
<ul>
<li v-for="category in categories">
<label>{{category.abc}}</label>
<input type="checkbox" :value="category" v-model="selectedCategory" #change="emitback(selectedCategory)"/>
</li>
</ul>
</div>
</script>
<!-- parent -->
<div id="demo">
<h2>
selected category:
</h2>
<ul>
<li v-for="category in selectedCategory">
{{category.abc}}
</li>
</ul>
<datafieldcheckbox :categories="product" #call="callfilteredproducts"></datafieldcheckbox>
</div>
script
Vue.component('datafieldcheckbox', {
template: '#grid-template',
props: {
categories: Array,
},
created(){
console.log(this.categories);
},
data: function () {
return {
selectedCategory:[]
}
},
methods: {
emitback(selectedVal){
this.$emit('call',selectedVal);
}
}
})
// bootstrap the demo
var demo = new Vue({
el: '#demo',
data: {
selectedCategory:[],
product:[
{
"id": "1",
"name": "Product1",
"abc": "EEE",
"skill": "Easy",
"color": "blue",
"price": 100.00
},
{
"id": 2,
"name": "Product2",
"abc": "EEE",
"skill": "Intermediate",
"color": "red",
"price": 120.00
},
{
"id": 3,
"name": "Product3",
"abc": "Office",
"skill": "Intermediate",
"color": "green",
"price": 190.00
}
]
},
methods:{
callfilteredproducts(event){
console.log(event);
this.selectedCategory = event
}
}
})
demo Jsfiddle
Related
I have a data coming from API. It is an array of "houses".
Code looks like this:
<template>
<div class="search__sort">
<input v-model="search" placeholder="Search for a house">
<button class="sort__button">Price</button>
<button class="sort__button">Size</button>
</div>
<div v-for="house in houses" :key="house.id" class="house">
<router-link :to="{ name: 'HouseDetails', params: { id: house.id}}" >
<h2>ID = {{ house }}</h2>
<h3> {{ house.location.street}} </h3>
<img :src="house.image" />
</router-link>
<button v-if="house.madeByMe" class="delete" #click="deleteHouse(house.id)">Delete</button>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Houses',
data(){
return {
houses: [],
}
},
created() {
this.getHouses();
},
methods: {
getHouses(){
// GET request using axios with set headers
const headers = { "CENSORED": "CENSORED" };
axios.get('myAPI', { headers })
.then(response => this.houses = response.data);
},
deleteHouse(id) {
const headers = { "CENSORED": "CENSORED" };
axios.delete('myAPI' + id, { headers })
.then(response => {
console.log(response);
})
.catch(function (error) {
console.log(error.response);
});
},
},
}
</script>
I somehow need to implement the filter by text input, so that for example, if user types a city name it will show all of those houses or a street name to filter that by street.
Any suggestions how I can do that with code that I already have?
You can use computed property:
new Vue({
el: '#demo',
data() {
return {
search: '',
houses: [{ "id": 2, "image": "myAPI/house1.jpg", "price": 123, "rooms": { "bedrooms": 1, "bathrooms": 1 }, "size": 500, "description": "oui", "location": { "street": "street 20", "city": "assas", "zip": "asasdd" }, "createdAt": "2020-05-07", "constructionYear": 2000, "hasGarage": false, "madeByMe": false }, { "id": 3, "image": "myAPI/house1.jpg", "price": 123, "rooms": { "bedrooms": 1, "bathrooms": 1 }, "size": 500, "description": "oui", "location": { "street": "street 20", "city": "adb", "zip": "asasdd" }, "createdAt": "2020-05-07", "constructionYear": 2000, "hasGarage": false, "madeByMe": false },{ "id": 4, "image": "myAPI/house1.jpg", "price": 123, "rooms": { "bedrooms": 1, "bathrooms": 1 }, "size": 500, "description": "oui", "location": { "street": "street 20", "city": "bbb", "zip": "asasdd" }, "createdAt": "2020-05-07", "constructionYear": 2000, "hasGarage": false, "madeByMe": false }],
}
},
computed: {
filteredHouses(){
return this.houses.filter(h => h.location.city.toLowerCase().includes(this.search.toLowerCase()))
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div class="search__sort">
<input v-model="search" placeholder="Search for a house">
<button class="sort__button">Price</button>
<button class="sort__button">Size</button>
</div>
<div v-for="house in filteredHouses" :key="house.id" class="house">
<h3> {{ house.location.city}} </h3>
<img :src="house.image" />
</div>
</div>
You will want to distinguish the difference between houses and displayedHouses such that, displayedHouses is your filtered array.
<h2>ID = {{ house }}</h2> is not going to play well with your testing
displayedHouses will be a computed looking something like:
computed:
{
/**
* #return {array} List of displayed houses from search input
*/
displayedHouses()
{
if (!this.houses || !this.houses.length)
{
return []
}
if (!this.search)
{
return this.houses
}
return this.houses.filter( (house) =>
{
return house.city.includes(this.search) || house.state.includes(this.search) // || whatever else you want
})
}
},
I'm working with BootstrapVue. I have following problem - I have a select dropdown in my parent.vue where I select my ID (as you can see it's my props) and I want to compare this with my json file...
Now I need to do following:
Check my selected ID (from parent.vue) with my json file and find the correct ID
Put all Articel in my dropdown selection
emit Rank of selected Articel back to parent
I don't have any clue how to solve that with a nested JSON File.. I think I have to use a v-for loop..
Thanks in advance for helping me out!
my code:
<template>
<b-card>
<div class="mt-2">CLOTHING ITEM</div>
<b-form-select type="text"></b-form-select>
</b-card>
</template>
<script>
import json from './json/ID.json'
export default {
name: "customerChoice",
data() {
return {
json: json,
}
},
props: ["ID"]
}
</script>
my nested json:
[
{
"ID": "1111",
"Product": {
"1": {
"Articel": "Jeans",
"Rank": "1"
},
"2": {
"Articel": "T-Shirt",
"Rank": "2"
}
}
},
{
"ID": "2222",
"Product": {
"1": {
"Articel": "Hoodie",
"Rank": "2"
},
"2": {
"Articel": "Jeans",
"Rank": ""
}
}
},
{
"ID": "3333",
"Product": {
"1": {
"Articel": "Socks",
"Rank": "1"
}
}
}
]
If I understand you correctly, take a look at following snippet:
Vue.component('Child', {
template: `
<b-card>
<div class="mt-2">CLOTHING ITEM</div>
<b-form-select type="text"
v-model="selected"
:options="articles"
text-field="Articel"
value-field="Rank"
>
</b-form-select>
</b-card>
`,
data() {
return {
json: [
{ID: "1111", "Product": {"1": {"Rank": "1", "Articel": "Jeans"}, "2": {"Articel": "T-Shirt", "Rank": "2"}}},
{ID: "2222", "Product": {"1": {"Articel": "Hoodie","Rank": "2"}, "2": {"Articel": "Jeans", "Rank": ""}}},
{ID: "3333", "Product": {"1": {"Articel": "Socks", "Rank": "1"}}}
],
selected: null,
}
},
props: ["id"],
computed: {
articles() {
const res = []
const art = this.json.find(j => j.ID === this.id)
for(let key in art.Product) {
res.push(art.Product[key])
}
return res
}
},
watch: {
selected() {
this.$emit('changed', this.selected)
}
}
})
new Vue({
el: '#demo',
data() {
return {
parentId: '1111',
rank: ''
}
},
methods: {
rankReceived(val) {
console.log(val)
this.rank = val
}
}
})
<script src="//unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<div id="demo">
<h3>{{rank}}</h3>
<Child :id="parentId" #changed="rankReceived" />
</div>
This is the dropdown component used to give a list of all grids in all pages. There are multiple pages and grids within those pages.
<v-dropdown
:items="pageGrids"
:item-text="gridNamesAndPages"
return-object
/>
gridNamesAndPages is under methods:
gridNamesAndPages: item => item.name + ' • (Page: ' + item.page_name.name + ')',
This is the method used to assign the empty array summaryGrids to all grids for this project:
getAllPageGrids() {
apiClientGet(
routes["pages.getAllPageGrids"],
null,
response => {
this.pageGrids.push(response.data);
}
);
},
The function in the controller:
public function getAllPageGrids()
{
return Auth::user()->client->grids()->get();
}
SummaryGrids are in this format. There could be multiple grids so whilst this only shows 3 there could be 100:
[
{
"id": 3,
"name": "AS",
"grid_cols": [
{
"id": 16,
"grid_id": 3,
"order": 1,
"header": "Col 1",
}
],
"page_name": {
"name": "Page 1"
}
},
{
"id": 4,
"name": "SF",
"grid_cols": [
{
"id": 21,
"grid_id": 4,
"header": "Name",
},
{
"id": 22,
"grid_id": 4,
"header": "Reference",
}
],
"page_name": {
"name": "Page 1"
}
},
{
"id": 5,
"name": "WE",
"grid_cols": [
{
"id": 24,
"grid_id": 5,
"header": "Name",
}
],
"page_name": {
"name": "Page 2"
}
}
]
However I continue to get this error:
I can't see anything wrong with the way the code is structured. Would anyone know if I've actually written it incorrectly?
(On request I've also included the custom v-dropdown component)
<template>
<v-select
:class="`text-field-${color || 'white'}`"
outlined dense
v-on="$listeners" v-bind="$attrs"
>
<slot>
<!-- -->
</slot>
</v-select>
</template>
<script>
export default {
props: {
color: {
type: String|null,
default: null
}
},
};
</script>
I'm currently getting data from themoviedb.com API. but I discovered the request doesn't include the specific genres for each movie. I created a separate json file that contains all the genres I need. Is there a way I can map data in my genres.json files to the remote API request?
{
"genres": [
{
"id": 28,
"name": "Action"
},
{
"id": 12,
"name": "Adventure"
},
{
"id": 16,
"name": "Animation"
},
{
"id": 35,
"name": "Comedy"
},
{
"id": 80,
"name": "Crime"
},
{
"id": 99,
"name": "Documentary"
},
{
"id": 18,
"name": "Drama"
},
{
"id": 10751,
"name": "Family"
},
{
"id": 14,
"name": "Fantasy"
},
{
"id": 36,
"name": "History"
},
{
"id": 27,
"name": "Horror"
},
{
"id": 10402,
"name": "Music"
},
{
"id": 9648,
"name": "Mystery"
}
]
}
This is how you might do that.
Basically with Vue, you want to create a computed value that maps over the response from the movie API and adds the genre information to the response.
console.clear()
const genres = [
{
"id": 28,
"name": "Action"
},
{
"id": 12,
"name": "Adventure"
},
{
"id": 16,
"name": "Animation"
},
{
"id": 35,
"name": "Comedy"
},
{
"id": 80,
"name": "Crime"
},
{
"id": 99,
"name": "Documentary"
},
{
"id": 18,
"name": "Drama"
},
{
"id": 10751,
"name": "Family"
},
{
"id": 14,
"name": "Fantasy"
},
{
"id": 36,
"name": "History"
},
{
"id": 27,
"name": "Horror"
},
{
"id": 10402,
"name": "Music"
},
{
"id": 9648,
"name": "Mystery"
}
]
new Vue({
el: "#app",
data:{
genres,
movies: null
},
computed:{
moviesWithGenre(){
// if the movies haven't been populated from the AJAX response yet
// return an empty array
if (!this.movies) return []
return this.movies.map(movie => {
return {
// add all the existing movie properties
...movie,
// add the genres
genres: movie.genre_ids
// remove the genres we don't know
.filter(id => this.genres.map(g => g.id).includes(id))
// get the name
.map(id => this.genres.find(g => g.id === id).name)
}
})
}
},
created(){
var url = "https://api.themoviedb.org/3/movie/popular?api_key=8e3003c0c81633dc53b9d15ffa3399e1&language=en-US&page=1"
axios.get(url)
.then(response => this.movies = response.data.results)
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>
<div id="app">
<ul>
<li v-for="movie in moviesWithGenre">
{{movie.original_title}}
<ul>
<li v-for="g in movie.genres">{{g}}</li>
</ul>
</li>
</ul>
</div>
I do not understand how any of this is related to vue.js as it looks like a pure javascript logic problem.
Here are some advices that could help you :
Rather than keeping an hardcoded list of Categories which is susceptible to get outdated and to break your application, i would recommend you to get them from the api itself :
https://developers.themoviedb.org/3/genres/get-movie-list
When having the result of both your genres and find request you could add the genre names to the object you are getting like so :
// Here the result of the 'genres' call
var genres = [...]
function getGenreName(genreId) {
var genre = genres.find(function(element) {
return element.id === genreId
})
if (!genre) return 'unknownGenre'
return genre.name
}
movieResults.map(function(movieResult) {
movieResult['genreNames'] = movieResult.genre_ids.map(function(genreId) {
return getGenreName(genreId)
})
return movieResult
})
I am trying to filter my results on multiple checkboxes.
Here is my JSFIDDLE
How do i write dynamic ng-model for the checkboxes for the filter to take reflect?
function MainCtrl($scope) {
$scope.languages = [
{ name: 'persian', _id : 0 },
{ name: 'English', _id : 1 },
{ name: 'spanish', _id : 2 }
];
$scope.bu = [
{ name: 'A', _id : 1 },
{ name: 'B', _id : 2 },
{ name: 'C', _id : 3 },
{ name: 'D', _id : 4 },
{ name: 'E', _id : 5 }
];
$scope.array = [
{
"id": 910,
"language": {
"_id": "333",
"name": "Persian",
"abbreviation": "PE"
},
"business_unit": {
"_id": "2",
"name": "B"
}
},
{
"id": 909,
"language": {
"_id": "456",
"name": "English",
"abbreviation": "EN"
},
"business_unit": {
"_id": "3",
"name": "C"
}
},
{
"id": 908,
"language": {
"_id": "456",
"name": "Spanish",
"abbreviation": "SP"
},
"business_unit": {
"_id": "4",
"name": "D"
}
},
{
"id": 911,
"language": {
"_id": "343",
"name": "German",
"abbreviation": "GE"
},
"business_unit": {
"_id": "5",
"name": "E"
}
},
{
"id": 912,
"language": {
"_id": "696",
"name": "Russian",
"abbreviation": "RU"
},
"business_unit": {
"_id": "1",
"name": "A"
}
}]
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="MainCtrl">
<li ng-repeat="o in languages" ng-model="lang.language.name">
<input type="checkbox">
{{o.name}},
`</li>
<br><br><br>
<li ng-repeat="o in bu">
<input type="checkbox" ng-model="bu.business_unit.name">
{{o.name}},
`</li>
<br><br><br>
<div ng-repeat="arr in array filter : lang | filter : bu">
{{arr.language.name}} "and" {{arr.business_unit.name}}
</div>
<div>
You can use custom filter to achieve your goal:
custom fileter:
filter('myFilter', function() {
return function(items, search) {
var filterItems = {
search: search,
result: []
};
if (!search.needFilter) {
return items;
}
angular.forEach(items, function(value, key) {
if (this.search.language[value.language.name] === true || this.search.business_unit[value.business_unit.name] === true) {
this.result.push(value);
}
}, filterItems);
return filterItems.result;
};
})
HTML:
<p>Search by Language:</p>
<li ng-repeat="o in languages">
<input type="checkbox" ng-model="search.language[o.name]"> {{o.name}}
</li>
<p>Search by Unit:</p>
<li ng-repeat="o in bu">
<input type="checkbox" ng-model="search.business_unit[o.name]"> {{o.name}}
</li>
<p><b>Result:</b></p>
<div ng-repeat="arr in array | myFilter : search:false ">
{{arr.language.name}} "and" {{arr.business_unit.name}}
</div>
For more details see PLUNKER DEMO