Polymer 2.0 iron-localstorage two arrays - javascript

I'm trying to make a shopping cart in polymer And I do not have much knowledge
How do I insert a selected data in template dom-repeat to an array binding to iron localsotage e.model.item it does not work.
<dom-module id="shop-cart">
<template>
<iron-ajax url="list.json" last-response="{{ListProducts}}" auto>
</iron-ajax>
<template is="dom-repeat" items="{{ListProducts}}">
<p style="display:block;width:400px">
<span>{{item.code}}</span>
<span>{{item.title}}</span>
<paper-button raised class="indigo" on-
click="addProduct">Add</paper-button>
<br/>
</p>
</template>
<iron-localstorage name="my-app-storage"
value="{{Orders}}"
on-iron-localstorage-load-empty="initializeDefaultOrders"
></iron-localstorage>
<template is="dom-repeat" items="Orders" as="order">
<div>
<p>{{order.code}}</p>
<p>{{order.title}}</p>
</div>
</template>
</template>
<script>
class ShopCart extends Polymer.Element {
static get is() {
return 'shop-cart';
}
static get properties() {
return {
Product: {
type: String
},
Orders: {
type: Array,
value() {
return [
{
code:'',
title:'',
}
];
},
},
ListProducts: {
type: Array,
value() {
return [];
},
}
}
}
initializeDefaultOrders() {
this.Orders = {
code:'',
title:''
}
};
addProduct(e) {
this.Product= e.model.item.title;
this.push('Orders',this.Product);
this.set('Product','');
}
deleteProduct(e) {
this.splice('Orders', e.model.index, 1);
}
}
window.customElements.define(ShopCart.is, ShopCart);
</script>
</dom-module>
<shop-cart></shop-cart>

The value passed to your method, addProduct(e), has nothing to do with the data model of the item of ListProducts.
Here is an example of shopping cart that binds the selection (a checkbox being checked) to a property of the item, item.selected.
https://github.com/renfeng/android-repository/blob/master/elements/android-sdk-manager.html#L267-L297
If checkboxes are not desirable, you can add a custom attribute to your button. e.g. selected
The following works only for Polymer 1.
<paper-button raised class="indigo" on-click="addProduct" selected="[[item.title]]">Add</paper-button>
And, have the following line to retrieve the title of the item selected.
this.Product= e.target.getAttribute("selected");
For Polymer 2, here is your fix.
https://github.com/renfeng/stackoverflow-question-44534326/commit/b2a4226bd5a1f5da7fa2d5a8819c53c65df7c412
Custom attribute has been proposed for Polymer 2, but not seem to be accepted for this moment. See https://github.com/Polymer/polymer/issues/4457

Related

v-for with model vuejs

I need to execute a v-for, however I do not know how to add a v-model for each different component inside of v-for;
<template>
<ProfilePasswordField
v-for="(item, index) in profilePasswordItems"
:key="index"
:profilePasswordItem="item"
v-model="???"
>
</template>
This v-for will always be three items and I want to name the v-model's as: ['passaword', 'newPassword', confirmNewPassword']
How can I add those names dinamically for the v-model inside v-for?
I tried to do a list inside data() but it did not work. Something like that:
data (){
return{
listPassword: ['passaword', 'newPassword', 'confirmNewPassword']
}
},
methods: {
method1 () {
console.log(this.passaword)
console.log(this.newPassword)
console.log(this.confirmNewPassword)
}
}
The v-model directives cannot update the iteration variable itself therefore we should not use a linear array item in for-loop as the v-model variable.
There is another method you can try like this-
In the parent component-
<template>
<div>
<ProfilePasswordField
v-for="(item, index) in listPassword"
:key="index"
:profilePasswordItem="item"
v-model="item.model"
/>
<button #click="method1()">Click to see changes</button>
</div>
</template>
<script>
export default {
name: "SomeParentComponent",
data() {
return {
listPassword: [
{ model: "passaword" },
{ model: "newPassword" },
{ model: "confirmNewPassword" },
],
};
},
methods: {
method1() {
this.listPassword.forEach((item) => {
console.log(item.model);
});
},
},
}
</script>
And in your ProfilePasswordField you can emit the input event to listen to the respected changes in v-model binding. For example, the ProfilePasswordField component could be like this-
<template>
<v-text-field :value="value" #input="$emit('input', $event)"/>
</template>
<script>
export default {
name: "ProfilePasswordField",
props: {
value: {
required: true
}
}
</script>
In the parent component's console, you should see the changes made by the child component.

Why not my vue component not re-rendering?

I have a question why not this component, not re-rendering after changing value so what I'm trying to do is a dynamic filter like amazon using the only checkboxes so let's see
I have 4 components [ App.vue, test-filter.vue, filtersInputs.vue, checkboxs.vue]
Here is code sandbox for my example please check the console you will see the value changing https://codesandbox.io/s/thirsty-varahamihira-nhgex?file=/src/test-filter/index.vue
the first component is App.vue;
<template>
<div id="app">
<h1>Filter</h1>
{{ test }}
<test-filter :filters="filters" :value="test"></test-filter>
</div>
</template>
<script>
import testFilter from "./test-filter";
import filters from "./filters";
export default {
name: "App",
components: {
testFilter,
},
data() {
return {
filters: filters,
test: {},
};
},
};
</script>
so App.vue that holds the filter component and the test value that I want to display and the filters data is dummy data that hold array of objects.
in my test-filter component, I loop throw the filters props and the filterInputs component output the input I want in this case the checkboxes.
test-filter.vue
<template>
<div class="test-filter">
<div
class="test-filter__filter-holder"
v-for="filter in filters"
:key="filter.id"
>
<p class="test-filter__title">
{{ filter.title }}
</p>
<filter-inputs
:value="value"
:filterType="filter.filter_type"
:options="filter.options"
#checkboxChanged="checkboxChanged"
></filter-inputs>
</div>
</div>
<template>
<script>
import filterInputs from "./filterInputs";
export default {
name: "test-filter",
components: {
filterInputs,
},
props:{
filters: {
type: Array,
default: () => [],
},
value: {
type: Array,
default: () => ({}),
},
},
methods:{
checkboxChanged(value){
// Check if there is a array in checkbox key if not asssign an new array.
if (!this.value.checkbox) {
this.value.checkbox = [];
}
this.value.checkbox.push(value)
}
};
</script>
so I need to understand why changing the props value also change to the parent component and in this case the App.vue and I tried to emit the value to the App.vue also the component didn't re-render but if I check the vue dev tool I see the value changed but not in the DOM in {{ test }}.
so I will not be boring you with more code the filterInputs.vue holds child component called checkboxes and from that, I emit the value of selected checkbox from the checkboxes.vue to the filterInputs.vue to the test-filter.vue and every component has the value as props and that it if you want to take a look the rest of components I will be glad if you Did.
filterInpust.vue
<template>
<div>
<check-box
v-if="filterType == checkboxName"
:options="options"
:value="value"
#checkboxChanged="checkboxChanged"
></check-box>
</div>
</template>
<script>
export default {
props: {
value: {
type: Object,
default: () => ({}),
},
options: {
type: Array,
default: () => [],
},
methods: {
checkboxChanged(value) {
this.$emit("checkboxChanged", value);
},
},
}
</script>
checkboxes.vue
<template>
<div>
<div
v-for="checkbox in options"
:key="checkbox.id"
>
<input
type="checkbox"
:id="`id_${_uid}${checkbox.id}`"
#change="checkboxChange"
:value="checkbox"
/>
<label
:for="`id_${_uid}${checkbox.id}`"
>
{{ checkbox.title }}
</label>
</div>
</div>
<template>
<script>
export default {
props: {
value: {
type: Object,
default: () => ({}),
},
options: {
type: Array,
default: () => [],
},
}
methods: {
checkboxChange(event) {
this.$emit("checkboxChanged", event.target.value);
},
},
};
</script>
I found the solution As I said in the comments the problem was that I'm not using v-model in my checkbox input Vue is a really great framework the problem wasn't in the depth, I test the v-model in my checkbox input and I found it re-render the component after I select any checkbox so I search more and found this article and inside of it explained how we can implement v-model in the custom component so that was the solution to my problem and also I update my codeSandbox Example if you want to check it out.
Big Thaks to all who supported me to found the solution: sarkiroka, Jakub A Suplick

How to reference a child component from the parent in Vue

I'm trying to figure out the Vue-way of referencing children from the parent handler.
Parent
<div>
<MyDropDown ref="dd0" #dd-global-click="ddClicked"></MyDropDown>
<MyDropDown ref="dd1" #dd-global-click="ddClicked"></MyDropDown>
<MyDropDown ref="dd2" #dd-global-click="ddClicked"></MyDropDown>
</div>
export default {
methods: {
ddClicked: function(id) {
console.log("I need to have MyDropDown id here")
}
}
}
Child
<template>
<h1>dropdown</h1>
<Button #click="bclick"></Button>
</template>
export default {
methods: {
bclick: function() {
this.$emit('dd-global-click')
}
}
}
In the parent component I need to see which dropdown was clicked.
What I've tried so far
I tried to set "ref" attribute in the parent. But I can't refer to this prop within the child component. Is there a way to do it? There is nothing like this.ref or this.$ref property.
I tried to use $event.targetElement in the parent, but it looks like I'm mixing Real DOM and Vue Components together. $event.targetElement is a DOM like . So in the parent I have to go over the tree until I find my dropdown. It is ugly I guess.
I set an additional :id property for the dropdown making it the copy of the 'ref' property. In the blick and I called this.$emit('dd-global-click', this.id). Later in the parent I check this.$refs[id]. I kind of works, but I'm not really content with it, because I have to mirror attributes.
Using the _uid property didn't work out either. On top of that, I think, that since it starts with an underscore it is not a recommended way to go.
It seems like a very basic task, so there must be a simplier way to achieve this.
If this custom dropdown element is the top level one (the root element) in the component, you could access the native DOM attributes (like id, class, etc) via this.$el, once it's mounted.
Vue.component('MyDropdown', {
template: '#my-dropdown',
props: {
items: Array
},
methods: {
changed() {
this.$emit('dd-global-click', this.$el.id);
}
}
})
new Vue({
el: '#app',
data: () => ({
items: [
{
id: 'dropdown-1',
options: ['abc', 'def', 'ghi']
},
{
id: 'dropdown-2',
options: ['jkl', 'lmn', 'opq']
},
{
id: 'dropdown-3',
options: ['rst', 'uvw', 'xyz']
}
]
}),
methods: {
ddClicked(id) {
console.log(`Clicked ID: ${id}`);
}
}
})
Vue.config.devtools = false;
Vue.config.productionTip = false;
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.11"></script>
<div id="app">
<my-dropdown
v-for="item of items" :key="item.id"
:id="item.id"
:items="item.options"
#dd-global-click="ddClicked">
</my-dropdown>
</div>
<script id="my-dropdown" type="text/x-template">
<select #input="changed">
<option v-for="item of items" :key="item" :value="item">
{{item}}
</option>
</select>
</script>

Vue.js checkbox component multiple instances

I have a list of filters using checkboxes. I'm trying to make each checkbox it's own components. So I loop through my list of filters adding a checkbox component for each filter. The Vue.js documentation says that if I have multiple checkboxes that use the same model that array will get updated with the value of the checkboxes. I see that working if the group of checkboxes is part of the parent component. But if I make the checkbox a component and add each checkbox component in a loop then the model doesn't update as expected.
How can I have a checkbox component that updates an array on the parent? I know I can do this with emitting an event for a method on the component that updates the array but the Vue documentation makes it seems like the framework does this for you.
Here is a code sample I've been playing around with https://www.webpackbin.com/bins/-KwGZ5eSofU5IojAbqU3
Here is a working version.
<template>
<div class="filter-wrapper">
<input type="checkbox" v-model="internalValue" :value="value">
<label>{{label}}</label>
</div>
</template>
<script>
export default {
props: ['checked','value', 'label'],
model: {
prop: "checked"
},
computed:{
internalValue: {
get(){return this.checked},
set(v){this.$emit("input", v) }
}
}
}
</script>
Updated bin.
The answer given by #Bert is right. I just want to complete the picture with the list of components and how thay are integrated. As this is a useful pattern.
Also including Select All functionality
ListItem.vue
<template>
<div class="item">
<input type="checkbox" v-model="internalChecked" :value="item.id" />
... other stuff
</div>
</template>
<script>
export default {
// Through this we get the initial state (or if the parent changes the state)
props: ['value'],
computed:{
internalChecked: {
get() { return this.value; },
// We let the parent know if it is checked or not, by sending the ID
set(selectedId) { this.$emit("input", selectedId) }
}
}
}
</script>
List.vue
<template>
<div class="list">
<label><input type="checkbox" v-model="checkedAll" /> All</label>
<list-item
v-for="item in items"
v-bind:key="item.id"
v-bind:item="item"
v-model="checked"
</list-item>
... other stuff
</div>
</template>
<script>
import ListItem from './ListItem';
export default {
data: function() {
return: {
// The list of items we need to do operation on
items: [],
// The list of IDs of checked items
areChecked: []
}
},
computed: {
// Boolean for checked all items functionality
checkedAll: {
get: function() {
return this.items.length === this.areChecked.length;
},
set: function(value) {
if (value) {
// We've checked the All checkbox
// Starting with an empty list
this.areChecked = [];
// Adding all the items IDs
this.invoices.forEach(item => { this.areChecked.push(item.id); });
} else {
// We've unchecked the All checkbox
this.areChecked = [];
}
}
}
},
components: {
ListItem
}
}
</script>
Once boxes get checked we have in checked the list of IDS [1, 5] which we can use to do operation on the items with those IDs

Reset values within dom-repeat

I'm using a dom-repeat in Polymer. The corresponding list includes an initial value that should be set whenever the list of the dom-repeat is reset. However, when the first element of the list keeps the same initial value, the value is not reset even though I completely empty the list before resetting it to the new value. Here's my minimum example:
<dom-module id="console-app">
<template>
<div id="command-selection">
<paper-dropdown-menu id="command" label="Function">
<paper-listbox slot="dropdown-content" selected="{{_commandIndex}}">
<paper-item>A</paper-item>
<paper-item>B</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</div>
<div id="parameters">
<template is="dom-repeat" items="[[_parameterData]]">
<parameter-block name="[[item.name]]" initial-value="[[item.initialValue]]" ></parameter-block>
</template>
</div>
</template>
<script>
class ConsoleApp extends Polymer.Element {
static get is() {
return 'console-app';
}
static get properties() {
return {
_commandIndex: {
type: Number,
value: -1,
observer: '_onIndexChange'
},
_parameterData: {
type: Array,
value: () => { return []; }
}
};
}
_onIndexChange() {
this.set('_parameterData', []);
switch (this._commandIndex) {
case 0:
this.set('_parameterData', [
{ name: 'AAA', initialValue: '111'},
{ name: 'BBB', initialValue: '123'}
]);
break;
case 1:
this.set('_parameterData', [
{ name: 'CCC', initialValue: '112'}
]);
break;
}
}
}
customElements.define(ConsoleApp.is, ConsoleApp);
</script>
</dom-module>
parameter-block:
<dom-module id="parameter-block">
<template>
<paper-input id="non-bool-value" label="[[name]]"
value="{{_value}}"></paper-input>
</template>
<script>
class ParameterBlock extends Polymer.Element {
static get is() {
return 'parameter-block';
}
static get properties() {
return {
_value: {
type: String,
value: () => { return ''; }
},
initialValue: {
type: String,
value: () => { return ''; },
observer: '_onInitialValueChange'
},
name: {
type: String,
value: () => { return ''; }
}
};
}
_onInitialValueChange() {
this.set('_value', this.initialValue);
}
}
customElements.define(ParameterBlock.is, ParameterBlock);
</script>
</dom-module>
When the index of the dropdown menu changes I reset _parameterData to [] and would assume that after that all future changes to _parameterData are evaluated as new elements. However, it seems like the list remembers the previous initial value after all as the corresponding listener is not called and previous changes to the first text element don't reset to 111 even though I'm changing the selection. If I use different initial values everything works fine, so I assume that I need to tell Polymer somehow to properly reset the elements, but how?
Since, you were only observing the initialValue the application will not know that the initialValue you were changing is for different name. That is why it is not resetting to default values you assigned.
You will need to observe both properties name and initialValue. So, change your observer code to :
static get observers() {
return [
'_onInitialValueChange(name, initialValue)'
]
}
and your method to:
_onInitialValueChange(name, initialValue) {
this.set('_value', this.initialValue);
}
I have updated the plnkr link provided.

Categories

Resources