Polymer2.0 - is it possible to set default value in dom-repeat? - polymer-2.x

I am trying to set the default value in dom-repeat.
In below example, I am trying to display default image(http://img04.deviantart.net/8465/i/2009/260/f/a/blender__texture_dummy_by_3d_asuarus.jpg) in dom repeat if the image is not available or undefined
I think , we cant use doublepipe operator in the expression [[item.image]]
HTML:
<head>
<base href="https://polygit.org/polymer+v2.0.0/shadycss+webcomponents+1.0.0/components/">
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-custom></x-custom>
<dom-module id="x-custom">
<template>
<style>
.test{
display:inline;
float:left;
border:1px solid black;
margin:5px;
padding:5px;
text-align:center;
}
</style>
<div> Employee list: </div>
<template is="dom-repeat" items="{{employees}}">
<div class="test">
<div># [[index]]</div>
<div>First name: <span>[[item.first]]</span></div>
<div>Last name: <span>[[item.last]]</span></div>
<div><img src="[[item.image]]" width="50px"></div>
</div>
</template>
</template>
</dom-module>
JS:
class XCustom extends Polymer.Element {
static get is() { return 'x-custom'; }
static get properties() {
return {
employees: {
type: Array,
value() {
return [
{first: 'Bob', last: 'Smith',image:'https://dummyimage.com/300.png/09f/fff'},
{first: 'Adam', last: 'Gilchrist',image:'https://cdn.pixabay.com/photo/2015/03/04/22/35/head-659652_960_720.png'},
{first: 'Sally', last: 'Johnson'},
];
}
}
}
}
}
customElements.define(XCustom.is, XCustom);
Codepen- https://codepen.io/nagasai/pen/EvPdLB

No, we cannot use pipe operator. But:
If you are just after setting a default value for image if not found or null:
<object data="[[item.image]]" type="image/png" width="50px">
<img src="http://img04.deviantart.net/8465/i/2009/260/f/a/blender__texture_dummy_by_3d_asuarus.jpg" width="50px"/>
</object>
More at: Inputting a default image in case the src attribute of an html <img> is not valid?
For other items you can use <dom-if>:
<span>
<template is="dom-if" if="[[!item.first]]">DefaultValue
</template>
[[item.first]]
</span>
I hope this helps.

Related

How to appendChild a component in DOM with VueJS?

I followed this tutorial https://css-tricks.com/creating-vue-js-component-instances-programmatically/
My component :
const button = Vue.component('button', {
props: {
id: String,
color: String
},
data: function() {
return {
count: 0
}
},
template:
`
<div class="button">
{{ count }}
</div>
`
});
The html :
<html>
<head>
<title>Test</title>
</head>
<body>
<div id="app">
<main id="main" ref="container">
<span #click="add">Add</span>
</main>
</div>
</body>
<script src="vue.js"></script>
<script src="app.js"></script>
</html>
All is fine but at this step I get the error "instance is not a html node" How to make vue component as a html node ?
ComponentClass = Vue.extend(button)
instance = new ComponentClass()
this.$refs.container.appendChild(instance.$el)

bootstrap-vue multi level drop down

i'm using bootstrap-vue and i have a multi level drop down menu (for categories) . this is official site example :
https://bootstrap-vue.org/docs/components/dropdown
<b-dropdown id="dropdown-1" text="Dropdown Button" class="m-md-2">
<b-dropdown-item>First Action</b-dropdown-item>
<b-dropdown-item>Second Action</b-dropdown-item>
</b-dropdown>
but i don't know how to create a multi level menu (i copy drop downs inside each other but it does not work) ! it has only 1 level drop down example ! how can i create a multi level one ?
tnx
So as I mentioned in my comments you can wrap b-dropdown events and do something custom like this:
window.onload = () => {
new Vue({
el: '#app',
data() {
return {
name: 'BootstrapVue',
isDropdown2Visible: false
}
},
mounted: function () {
this.$root.$on('bv::dropdown::show', bvEvent => {
if(bvEvent.componentId === 'dropdown-2') {
this.isDropdown2Visible = true;
}
})
this.$root.$on('bv::dropdown::hide', bvEvent => {
if(bvEvent.componentId === 'dropdown-2') {
this.isDropdown2Visible = false;
}
if(this.isDropdown2Visible) {
bvEvent.preventDefault()
}
})
}
})
}
body { padding: 1rem; }
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-dropdown id="dropdown-1" text="Dropdown Button 1" class="m-md-2">
<b-dropdown-item>First Action 1</b-dropdown-item>
<b-dropdown-item>Second Action 1</b-dropdown-item>
<b-dropdown id="dropdown-2" text="Dropdown Button 2" class="m-md-2">
<b-dropdown-item>First Action 2</b-dropdown-item>
<b-dropdown-item>Second Action 2</b-dropdown-item>
</b-dropdown>
</b-dropdown>
</div>
You can try something like this
This snippet contains logic for one level menu.You can edit code as
per your requirement
JSBin Link
new Vue({
el: "#app",
data: {
menu: [
{ title : 'one'},
{ title : 'two'},
{ title : 'three',showSubMenu : false,
children : [
{ title : 'four'},
{ title : 'five'},
]},
]
},
methods : {
toogleItem(index){
if(this.menu[index].children){
if(!this.menu[index].showSubMenu){
this.menu[index].showSubMenu = true
} else {
this.menu[index].showSubMenu = false
}
}
}
}
})
.sub-menu{
position: absolute;
min-width: 10rem;
padding: .5rem 0;
margin: .125rem 0 0;
font-size: 1rem;
color: #212529;
text-align: left;
list-style: none;
background-color: #fff;
background-clip: padding-box;
border: 1px solid rgba(0,0,0,.15);
border-radius: .25rem;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver" crossorigin="anonymous"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<!-- Load the following for BootstrapVueIcons support -->
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue-icons.min.js"></script>
</head>
<body>
<div id="app">
<b-dropdown id="dropdown-1" text="Dropdown Button" class="m-md-2">
<b-dropdown-item
v-for="(item,index) in menu"
:key="index"
#mouseover.native="toogleItem(index)"
#mouseout.native="toogleItem(index)">
<span>{{item.title}} <b-icon-caret-down-fill :scale="0.6" v-if="item.children"></b-icon-caret-down-fill></span>
<div v-if="item.children" class="sub-menu" v-show="item.showSubMenu">
<b-dropdown-item v-for="(item,index) in item.children" :key="index">{{item.title}}
</b-dropdown-item>
</div>
</b-dropdown-item>
</b-dropdown>
</div>
</body>
</html>

How can a Bootstrap-vue tooltip text be changed conditionally?

How can a Bootstrap-vue tooltip text be changed conditionally by a checkbox? How can the tooltip text be accessed to change it? Any help would be greatly appreciated.
Vue component where a checkbox is attempting to change a tooltip:
<template>
<div class="text-center">
<b-button v-b-tooltip.hover.right="tooltipText" variant="outline-primary">
<div v-bind:class="{ active: checkbox1 }">
{{ username }}
</div>
</b-button>
</div>
</template>
<script>
export default {
props: ['username', 'checkbox1'],
data() {
return {
show: true,
tooltipTextContent: 'hello tooltip',
}
},
methods: {
tooltipText() {
if (!this.checkbox1) {
return this.tooltipTextContent
} else {
return `${this.tooltipTextContent} changed`
}
}
},
}
</script>
<style scoped>
.active {
color: red;
}
</style>
You just have to bind a value to the tooltip text that can be changed, like computed:
new Vue({
el: "#app",
data: {
username: 'Username1',
checkbox1: false,
tooltipTextContent: 'block'
},
computed: {
tooltipText() {
if (!this.checkbox1) {
return this.tooltipTextContent
} else {
return `${this.tooltipTextContent} changed`
}
}
}
})
.active {
color: red;
}
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver" crossorigin="anonymous"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<!-- Load the following for BootstrapVueIcons support -->
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue-icons.min.js"></script>
<div id="app">
<div class="text-center">
<b-button v-b-tooltip.hover.right="tooltipText" variant="outline-primary">
<div v-bind:class="{ active: checkbox1 }">
{{ username }}
</div>
</b-button>
</div>
<b-form-checkbox id="checkbox-1" v-model="checkbox1" name="checkbox-1">
Change tooltip text?
</b-form-checkbox>
</div>

Why won't my click event in Vue.js fire?

I'm trying to use Vue's on-click directive on a div but it does not fire as intended. When I click the .demo class nothing happens; I should get a 'test clicked' in the console. I don't see any errors in the console, so I don't know what am I doing wrong.
var app = new Vue({
el: '#app',
data: {
title: 'This is the first vue app',
name: 'ALRAZY',
link: 'http://google.com',
attachRed: false
},
methods: {
changeLink: function() {
this.link = 'http://apple.com'
}
}
})
body {
font-family: 'Trykker', 'Spectral SC', serif;
}
h1,h2,h3,h4,h5,h6 {
font-family: 'Spectral SC', serif;
}
p {
font-family: 'Trykker', serif;
}
.demo {
width: 100px;
height: 100px;
background-color: grey;
display: inline-block;
margin: 10px;
}
.red {
background: red;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css?family=Spectral+SC:400,400i,500,500i,600|Trykker" rel="stylesheet" >
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div class="container">
<div class="row">
<div id="app">
<h1>{{ title }} </h1>
<input type="text" v-model="name" name="">
<p> {{ name }}</p>
<button onclick="changeLink" class="btn btn-danger btn-lg">click to change</button>
<a :href="link" target="_blank">Link</a>
<!-- style-vue -->
<div class="demo" onclick="attachRed = !attachRed" :class="{red: attachRed}"></div>
<p v-if="show">You can see me!!!</p>
<p v-else>Do You see me??</p>
</div>
</div>
</div>
You're using the standard onclick attribute which is not going to trigger vue methods. Try using v-on:click="changeLink()" or #click="changeLink()" (I'm not entirely sure if the second is the correct syntax). That should resolve your problem.
Similarly, you can do #click="attachRed = !attachRed".

polymer 2 dom-repeat does not reflect when item is removed

I have a very simple application in Polymer 2. I have a static list of items which is displayed with dom-repeat.
I have a button for delete, on click i could see the item is removed from the list. But the dom-repeat is not refreshed. Its still the old code.
Can someone help how to reflect the changes on the screen:
code snippet is below:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-list/iron-list.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/app-storage/app-localstorage/app-localstorage-document.html">
<link rel="import" href="../../bower_components/polymer/lib/elements/dom-repeat.html">
<dom-module id="todo-list">
<template>
<style>
:host {
display: block;
}
.ibtn {
float: right;
}
.item {
width: 500px;
}
paper-icon-button {
color: grey;
}
.list-todo {
height: 700px;
text-align: left;
-webkit-text-fill-color: brown;
}
.list-todo ul li {
width: 500px;
font-family: sans-serif;
font-size: 20px;
}
.list-todo .btn-set {
float: right;
}
</style>
<!-- <app-localstorage-document key="app-store" data="{{todos}}"></app-localstorage-document> -->
<div class="list-todo">
<template is="dom-repeat" items="{{todos}}">
<ul>
<li>
<iron-icon icon="icons:arrow-forward"></iron-icon>
{{item}}
<span class="btn-set">
<paper-icon-button icon="create"></paper-icon-button>
<paper-icon-button icon="delete" on-tap="deleteTodo"></paper-icon-button>
<paper-icon-button icon="star"></paper-icon-button>
<span>
</li>
</ul>
</template>
</div>
</template>
<script>
/**
* #customElement
* #polymer
*/
class TodoList extends Polymer.Element {
static get is() { return 'todo-list'; }
static get properties() {
return {
todos: {
type: Object,
value: ["Build the code", "Check Sonar Issues", "Release the APP", "Deploy in Production", "Get Feedback"],
notify: true
}
};
}
populateTodoList() {
return this.todos;
}
deleteTodo(item) {
this.todos.splice(item.model.index, 1);
this.todos.flush;
}
}
window.customElements.define(TodoList.is, TodoList);
</script>
</dom-module>
Javascript splice removes the item from the array, but it does not mean the change is reflected in polymer shadowRoot.
To do this you have to use polymer array mutation methods. See this.
In your case will be:
this.splice('todos', item.model.index, 1);
Also, this.todos.flush; is not needed.
Another thing I detected (not related with this), are you sure you want to have <ul> inside the repeat? This created a bunch of list with just one item inside each list.
I suggest you to do this
<div class="list-todo">
<ul>
<template is="dom-repeat" items="{{todos}}">
<li>
<iron-icon icon="icons:arrow-forward"></iron-icon>
{{item}}
<span class="btn-set">
<paper-icon-button icon="create">create</paper-icon-button>
<paper-icon-button icon="crystal-icons:lens" on-tap="deleteTodo">delete</paper-icon-button>
<paper-icon-button icon="star">star</paper-icon-button>
<span>
</li>
</template>
</ul>
</div>
This way you just create one list.