Polymer 1.0 dynamically add options to menu - dynamic

Hi I am having some trouble getting a menu to add options dynamically. They idea is the selection of the first menu decides what the second menu contains. I have built this before successfully without polymer. And it semi-works with polymer. dropdown one gets its content from json based on the selection, dropdown two gets its content also from a json. This part works, the issue is when you make a selection from dropdown one and then change it, dropdown two doesn't delete the old selection. I got this working last time with a function that first deletes all dropdown two's children before repopulating the content. Issue with Polymer is once the childNodes are deleted the dropdown breaks and no other children can be added via data binding. tried adding native with plain JS which populates the menu but the children are not selectable(from what I have read this might be a bug). Also I believe data binding on dynamic items also doesnt work anymore. anyway here is what I have:
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/paper-material/paper-material.html">
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="../../../bower_components/paper-menu/paper-menu.html">
<link rel="import" href="../../../bower_components/paper-item/paper-item.html">
<link rel="import" href="../../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../../bower_components/iron-dropdown/demo/x-select.html">
<dom-module id="add-skill">
<template>
<paper-material elevation="1">
<paper-dropdown-menu id="ddMenu" attr-for-selected="value" >
<paper-menu class="dropdown-content" id="vendorSelect" on-iron-select="_itemSelected">
<template is="dom-repeat" items="{{vendorList}}">
<paper-item id="vendorName" value="item">[[item]]</paper-item>
</template>
</paper-menu>
</paper-dropdown-menu>
<paper-dropdown-menu>
<paper-menu class="dropdown-content" id="certificationSelect" on-iron-select="_itemSelected">
</paper-menu>
</paper-dropdown-menu>
<!-- testing ideas -->
<paper-dropdown-menu>
<paper-menu class="dropdown-content" id="test" on-iron-select="_itemSelected">
<option extends="paper-item"> Option </option>
<option extends="paper-item"> Option1 </option>
<option extends="paper-item"> Option2 </option>
</paper-menu>
</paper-dropdown-menu>
<paper-button on-click="_deleteElement">
Delete
</paper-button>
</paper-material>
<iron-ajax
id="vendorSubmit"
method="POST"
url="../../../addskill.php"
handle-as="json"
on-response="handleVendorResponse"
debounce-duration="300">
</iron-ajax>
<iron-ajax
id="certificationSubmit"
method="POST"
url="../../../addskill.php"
handle-as="json"
on-response="handleCertificationResponse"
debounce-duration="300">
</iron-ajax>
</template>
<script>
Polymer({
is: 'add-skill',
ready: function() {
this.sendVendorRequest();
this.vendorList = [];
this.certificationList = [];
},
sendVendorRequest: function() {
var datalist = 'vendor=' + encodeURIComponent('1');
//console.log('datalist: '+datalist);
this.$.vendorSubmit.body = datalist;
this.$.vendorSubmit.generateRequest();
},
handleVendorResponse: function(request) {
var response = request.detail.response;
for (var i = 0; i < response.length; i++) {
this.push('vendorList', response[i].name);
}
},
vendorClick: function() {
var item = this.$;
//var itemx = this.$.vendorSelect.selectedItem.innerHTML;
//console.log(item);
//console.log(itemx);
},
sendCertificationRequest: function(vendor) {
var datalist = 'vendorName=' + encodeURIComponent(vendor);
console.log('datalist: ' + datalist);
this.$.certificationSubmit.body = datalist;
this.$.certificationSubmit.generateRequest();
},
handleCertificationResponse: function(request) {
var response = request.detail.response;
//var vendorSelect = document.getElementById('vendorSelect');
for (var i = 0; i < response.length; i++) {
this.push('certificationList', response[i].name);
}
console.log(this.certificationList);
},
_itemSelected: function(e) {
var selectedItem = e.target.selectedItem;
if (selectedItem) {
this.sendCertificationRequest(selectedItem.innerText);
console.log("selected: " + selectedItem.innerText);
}
},
_removeArray: function(arr) {
this.$.certificationList.remove();
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
arr.splice(0, i);
arr.pop();
}
console.log(arr.length);
},
_deleteElement: function() {
var element = document.getElementById('certificationSelect');
while (element.firstChild) {
element.removeChild(element.firstChild);
}
},
_createElement: function() {
var doc = document.querySelector('#test');
var option = document.createElement('option');
option.extends = "paper-item";
option.innerHTML = "Option";
doc.appendChild(option);
}
});
</script>
</dom-module>
Any guidance is always appreciated

Here's a working version of your JSBin, which uses data binding and a <template is="dom-repeat"> to create new, selectable <paper-item> elements dynamically.
I'm not sure what specific issues you ran into when using data binding to stamp out the <paper-item> elements, but the important thing to remember in Polymer 1.0 is that when you modify an Array (or an Object) that is bound to a template, you need to use the new helper methods (like this.push('arrayName', newItem)) to ensure the bindings are updated.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<base href="http://element-party.xyz">
<script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="all-elements.html">
</head>
<body>
<dom-module id="x-module">
<template>
<paper-material elevation="1">
<paper-dropdown-menu>
<paper-menu class="dropdown-content" on-iron-select="_itemSelected">
<template is="dom-repeat" items="[[_menuItems]]">
<paper-item>[[item]]</paper-item>
</template>
</paper-menu>
</paper-dropdown-menu>
<paper-button on-click="_createItem">Add</paper-button>
</paper-material>
</template>
<script>
Polymer({
_createItem: function() {
this.push('_menuItems', 'New Option ' + this._menuItems.length);
},
_itemSelected: function() {
console.log('Selected!');
},
ready: function() {
this._menuItems = ['First Initial Option', 'Second Initial Option'];
}
});
</script>
</dom-module>
<x-module></x-module>
</body>
</html>

Related

changing values in .vue file of Vue JS project not working

I have found a tool called XLSX to JSON on github, which has been made using vuejs/sheetjs. git repo, This tool is available online via an interface - but recently it seems to have broken and I cant download my converted json file.
Therefore my intention was to clone the repo, and change some bits around to fix it (just console json file instead of DL).
I haven't used Vue js before. After looking through the index and the origins of the functions I saw that the whole page seems to be reliant on this app.vue file. However - when editing the values and reloading the webpage - theres no change what so ever!
App.vue:
<template>
<div class="col">
<div class="row">
<div id="dropZone" v-on:drop.prevent="parseXLSX($event)" v-on:dragend="cleanup" ondragenter="event.preventDefault();" ondragover="event.preventDefault(); event.dataTransfer.dropEffect='copy'" class="col drop-box">
<h2 class="text-center"> Drag your xlsx file here.</h2>
</div>
</div>
<div class="row">
<input type='file' id='inputFile' v-on:change="parseXLSX($event.target.files)">
<div v-if="hasDownload">
<a id="download"> Download Localalization JSON </a>
</div>
</div>
<div class="row">
<div class="col json-box">
<h2 class="text-center"> JSON Output</h2>
<pre id="output"> </pre>
</div>
</div>
<xlsx-footer></xlsx-footer>
</div>
</template>
<script>
import Footer from './components/footer.vue';
export default {
data() {
return {
hasDownload: false,
}
},
methods: {
parseXLSX(event) {
const XLSX = window.XLSX;
let file = this.getFile(event);
let workBook = null;
let jsonData = null;
if(file !== null) {
const reader = new FileReader();
const rABS = true;
reader.onload = (event) => {
// I WANT TO do edits but nothing seems to work
//console logs not working etc...
const data = event.target.result;
if(rABS) {
workBook = XLSX.read(data, {type: 'binary'});
jsonData = workBook.SheetNames.reduce((initial, name) => {
const sheet = workBook.Sheets[name];
initial[name] = XLSX.utils.sheet_to_json(sheet);
return initial;
}, {});
const dataString = JSON.stringify(jsonData, 2, 2);
document.getElementById('output').innerHTML = dataString.slice(0, 300).concat("...");
this.setDownload(dataString);
}
}
if(rABS) reader.readAsBinaryString(file);
else reader.readAsArrayBuffer(file);
}
},
getFile(item) {
if(item.dataTransfer !== undefined) {
const dt = item.dataTransfer;
if(dt.items) {
if(dt.items[0].kind == 'file') {
return dt.items[0].getAsFile();
}
}
}
else {
return item[0];
}
},
setDownload(json) {
this.hasDownload = true;
setTimeout(()=> {
const el = document.getElementById("download");
el.href = `data:text/json;charset=utf-8,${encodeURIComponent(json)}`;
el.download = 'localization.json';
}, 1000)
},
cleanup(event) {
console.log("Cleaned up Event", event);
}
},
components: {
'xlsx-footer': Footer,
}
}
</script>
main.js:
'use strict';
var _vue = require('vue');
var _vue2 = _interopRequireDefault(_vue);
var _app = require('./app.vue');
var _app2 = _interopRequireDefault(_app);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var app = new _vue2.default({
el: "#app",
render: function render(h) {
return h(_app2.default);
}
});
index.html:
<!DOCTYPE html>
<html>
<head>
<title> XLSX-TO-JSON </title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/tether/1.4.0/tether.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.11.3/xlsx.full.min.js"></script>
<link rel="stylesheet" type="text/css" href="./css/style.css">
</head>
<body>
<h1 class="title text-center"> XLSX-TO-JSON </h1>
<div id="app" class="container">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"> </script>
<script src="bin/bundle.js"></script>
<!-- <script src="assets/bundle.js"></script> -->
</body>
</html>
All I want to do is edit the functions in the app.vue file!
Any help would be great, cheers!
Try to modify the package.json file by adding "prod":"webpack" in the "scripts" brackets. Running npm run prod should recreate your bundle.js file after .vue files modification using the webpack.config.js provided.
Also you could use script test using npm run test which launch webpack-dev-server and enable hot reload which is more convinient for dev purpose.
When you make change in any vue js file you have run npm run prod and you have to either upload the whole project in the server or upload the public folder in the server

binding dynamic img in vuejs does not work for me

I have a dynamic img being pulled from an api using vue.js. For some strange reason, the image won't bind. I have tried both :src. and :attr but neither works. The url does display in the vue console inside of the data but can't get the image to display on the page. any help will go a long way.
<html>
<head>
<style></style>
</head>
<body>
<div class="container">
<div id="editor">
<img v-bind:src="PictureURL" />
</div>
</div>
<script type="text/javascript" src="https://unpkg.com/vue#2.0.3/dist/vue.js"></script>
<script>
new Vue({
el: "#editor",
data: {
PictureUrl: "",
},
created: function() {
this.getCurrentUser();
},
methods: {
getCurrentUser: function() {
var root = 'https://example.com';
var headers = {
accept: "application/json;odata=verbose"
}
var vm = this;
var __REQUESTDIGEST = '';
$.ajax({
url: root + "_api/Properties",
type: 'Get',
headers: headers,
success: function(data) {
vm.PictureUrl = data.d.PictureUrl;
}
})
},
}
})
</script>
</body>
</html>
Change <img v-bind:src="PictureURL" /> to <img v-bind:src="PictureUrl" />, so that you match the data item name. Vue should be giving you an error in the console about this.
https://jsfiddle.net/kch7sfda/
Example here.
You can try to:
1. add v-if to img element
2. rename PictureUrl to pictureUrl (first lowercase letter)

Vuejs 2 How to update v-model by component

I would like to create a component for i-check but I cannot get the v-model data during form submission.
I can do it via normal input element.
Below is an example. Thanks
<!DOCTYPE html><html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://unpkg.com/vue"></script>
<title>JS Bin</title>
</head>
<body>
<div id=wrap>
<ichecker id="test" checked v-model="formData.checkbox"></ichecker>
<!--<input type=checkbox checked v-model="formData.checkbox" />-->
<button v-on:click.prevent=submit()>Submit</button>
</div>
</body>
</html>
Vue.component('ichecker', {
props: ['id', 'checked'],
model: {
prop: 'checked',
event: 'change'
},
template: "<input type='checkbox' :id='id' />",
mounted: () => {
// var $el = jQuery(`#${this.id}`);
// $el.iCheck({.....
}
});
new Vue ({
el: '#wrap',
data: {
formData : {
checkbox : ''
}
},
methods: {
submit: function() {
document.body.appendChild(document.createTextNode(this.formData.checkbox?'true ':'false '));
// form submission
}
}
});
https://jsbin.com/jugerigeto/edit?html,js,output
You are in a quite particular scenario where the <input> itself is the root element of your component. So you can't use v-model if you want to listen to the native event, cause it only exists on v-on. v-model is just a shorcut thought, and you can do it easily like this:
HTML:
<ichecker :checked="formData.checkbox"
#change.native="formData.checkbox = $event.target.checked">
</ichecker>
JS:
Vue.component('ichecker', {
prop: ['checked'],
template: '<input type="checkbox" :checked="checked" />'
});
https://jsbin.com/suvonolita/edit?html,js,output
You may also want to do it without the native event, if the input is not your root node. Or you may really want v-model. The way to implement v-model on a custom component is described there: https://v2.vuejs.org/v2/guide/components.html#Customizing-Component-v-model

Vue.js watched data chang twice with only one request

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div id="app">
<div class="layui-input-block" style="width:510px;">
<form class="layui-form" action="">
<select v-model="form.entrCode">
<option value="">please select an entry</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</form>
</div>
</div>
</body>
</html>
<script src="//cdn.bootcss.com/vue/2.2.4/vue.min.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
action: '',
form: {
entrCode: '',
}
},
watch: {
action: function (val) {
if (val !== "add"){
var vm = this;
//$.get("/park/GetLEDDtl", { areaId: vm.form.code }, function (rs) {
// vm.form = rs;
//}, "json");
//simulate setting on ajax.success
vm.form = { "entrCode": "20" };
}
},
"form.entrCode": function (val, old) {
alert("【entryCode changed】 new:" + val + " old:" + old);
}
},
created: function () {
this.action = "edit";
}
});
</script>
Please look at my code. I've only set app.form = object once, why there are two value changed be watched?
First, it changes from '' to '20', which is what I'm expected, but suddenly it changes from 20 to undefined.
(The code patsed I commented ajax request, and set value directly.)
What just happened?
There is no option with the value you are setting the variable to. The select object cannot be synced up to show the value, so it reverts the value to undefined.

localStorage and updateView + windows 8

I have some items and I mark them as favorite by pressing a button, here is the code:
function AddToFavorites() {
//called when a shop is added as as a favorite one.
//first we check if already is favorite
var favoritesArray = getStoreArray();
var alreadyExists = exists();
if (!alreadyExists) {
favoritesArray.push(itemHolder);
var storage = window.localStorage;
storage.shopsFavorites = JSON.stringify(favoritesArray);
}
}
function exists() {
var alreadyExists = false;
var favoritesArray = getStoreArray();
for (var key in favoritesArray) {
if (favoritesArray[key].title == itemHolder.title) {
//already exists
alreadyExists = true;
}
}
return alreadyExists;
}
function getStoreArray() {
//restores our favorites array if any or creates one
var storage = window.localStorage;
var favoritesArray = storage.shopsFavorites;
if (favoritesArray == null || favoritesArray == "") {
//if first time
favoritesArray = new Array();
} else {
//if there are already favorites
favoritesArray = JSON.parse(favoritesArray);
}
return favoritesArray;
}
And I have a favorites.html to present those as a list.
The problem I have is that the list doesn't update automaticly every time I add or remove items.
Here is my code for that:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Αγαπημένα</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<link href="favoritesDetails.css" rel="stylesheet" />
<script src="favoritesDetails.js"></script>
</head>
<body>
<div class="favoritesDetails fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Αγαπημένα</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
<div class="mediumListIconTextItem">
<img src="#" class="mediumListIconTextItem-Image" data-win-bind="src: picture" />
<div class="mediumListIconTextItem-Detail">
<h4 data-win-bind="innerText: title"></h4>
<h6 data-win-bind="innerText: text"></h6>
</div>
</div>
</div>
<div id="basicListView" data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource : DataExample.itemList.dataSource,
itemTemplate: select('#mediumListIconTextTemplate')}">
</div>
</section>
</div>
</body>
</html>
And here is the JavaScript code:
// For an introduction to the Page Control template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
var dataArray = [], shopsArray = [];
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
var nav = WinJS.Navigation;
var ui = WinJS.UI;
shopsArray = getStoreArray();
if (shopsArray) {
for (var key in shopsArray) {
var group = { title: shopsArray[key].title, text: shopsArray[key].subtitle, picture: shopsArray[key].backgroundImage, description: shopsArray[key].description, phoneNumbers: shopsArray[key].content };
dataArray.push(group);
}
var dataList = new WinJS.Binding.List(dataArray);
// Create a namespace to make the data publicly
// accessible.
var publicMembers =
{
itemList: dataList
};
WinJS.Namespace.define("DataExample", publicMembers);
}
WinJS.UI.Pages.define("/pages/favoritesDetails/favoritesDetails.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
},
unload: function () {
},
updateLayout: function (element, viewState, lastViewState) {
}
});
})();
function getStoreArray() {
//restores our favorites array if any or creates one
var storage = window.localStorage;
var favoritesArray = storage.shopsFavorites;
if (favoritesArray == null || favoritesArray == "") {
//if first time
favoritesArray = new Array();
} else {
//if there are already favorites
favoritesArray = JSON.parse(favoritesArray);
}
return favoritesArray;
}
So how can I update the favorites HTML page when new favorites are stored/removed in the localDB? can i add event listeners there?
Is the code that stores favorites a part of the same app?
If so, I would consider adding the favorite to the underlying WinJS.Binding.list that you're using to bind to the ListView, and then store the updated list info in the DB, rather than trying to react to changes in the DB from the ListView.
Have a look at the following sample, which shows how to update a ListView dynamically:
http://code.msdn.microsoft.com/windowsapps/ListView-custom-data-4dcfb128/sourcecode?fileId=50893&pathId=1976562066
Hope that helps!