Polymer dom-if not working - javascript

I have this template dom-if using Polymer 1.X, and it is not working.
It is supposed to display 'Loading' when requirement.allLoaded is false and display the real content when requirement.allLoaded is true.
I switch the state of this variable in my test function. But it doesn't take effects.
//Properties
requirement: {
type:Object,
value: {
allLoaded: false,
tagsLoaded: false
}
}
//Test function
_testButton: function(){
console.log(this.requirement);
this.requirement.allLoaded = !this.requirement.allLoaded;
console.log(this.requirement);
},
<div id="modal-content">
<template is="dom-if" if={{!requirement.allLoaded}}>
<p>Loading</p>
</template>
<template is="dom-if" if={{requirement.allLoaded}}>
<iron-pages selected="[[selectedTab]]" attr-for-selected="name" role="main">
<details-tab name="details"></details-tab>
<bar-chart-tab name="barchart"></bar-chart-tab>
<live-data-tab name="livedata" shared-info='{{sharedInfo}}'></live-data-tab>
</iron-pages>
</template>
</div>
Note: I already used this structure to display/not display things in other project (with Polymer 2) and it was working.

Is it only the change that does not work? I.e. it shows correctly on load?
Try notifying Polymer of the change:
this.requirement.allLoaded = !this.requirement.allLoaded;
this.notifyPath('requirement.allLoaded');

You could also use this.set('property.subProperty', value) for Observable Changes.
In your case, that's this.set('requirement.allLoaded', !this.requirement.allLoaded);

Related

Using vanilla js append, vue.js loses refrence

Ill simplify the example. Basically i have multiple widgets on one page and i tought it would be a good practice not to copy all the widgets into v-dialog but use the refrence and apenned them into the dialog and back to the grid when needed. The problem is when i append my html into dialog and I try to run this.$refs vue loses track of infinite-loading componente... this.$refs does not contain ref="infinitiveLoading". If some1 can explain and maybe reccommend better practice.. thx
<div>
<div id="item_containerTest" ref="item_containerTest">
<span>Hello world</span>
<infinite-loading
ref="infinitiveLoading"
v-show="items.length !== 0 || this.loading"
#infinite="infiniteHandler"
>
<div slot="no-more"></div>
</infinite-loading>
</div>
<v-dialog v-model="scheduleDialog" id="dialog" ref="dialog"> </v-dialog>
</div>
//ignore itemID and columnID, i need them so i can append item back to the grid after dialog closes
openFullScreenDialog(itemId, columnId, title){
itemContainer = document.getElementById(`item_container${title}`);
dialog = document.getElementById("dialog");
dialog.append(itemContainer);
}
As Lucero said in the comments, you shouldn't manipulate the DOM with the classic javascript API. The breaks the shadow DOM of Vuejs (i.e. a runtime copy of the current DOM state in memory) and thus, its reactivity and components references.
If you have a content that have to be wrapped in different container depending on a prop for example, you can use slots for this :)
<template>
<div>
<div v-if="dialog">
<slot>
</div>
<v-dialog v-else v-model="openDialog">
<slot>
</v-dialog>
</div>
</template>
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
export default Vue.extends({
name: 'GridOrDialog',
props: {
dialog: { type: Boolean, default: false }
},
data() {
return {
openDialog: true,
}
}
})
</script>
This way, you just have to declare the content once, and it will be on a v-dialog if you sets the prop dialog to true.
<GridOrDialog dialog="isDialogMode">
<span>Hello world</span>
<infinite-loading
ref="infinitiveLoading"
v-show="items.length !== 0 || this.loading"
#infinite="infiniteHandler"
>
<div slot="no-more"></div>
</infinite-loading>
</GridOrDialog>

how to animate a custom-element of a dom-repeat in polymer 1.0

I'm trying to apply a cascaded-animation on a dom-repeat elements. when the element inside the repeat element is a paper-card or paper-material everything is fine but replacing it with a custom element removes the animation effect.
I added the animatable behavior to the element, but it doesn't work.
here is my list
<dom-module id="list-view">
<template>
<template id="list" is="dom-repeat" items={{records}} on-dom-change="_renderRepeat">
<task-element
title="{{item.title}}"
duration="{{item.duration}}"
project="{{item.project}}"
client="{{item.client}}"
id="{{item.id}}"
on-editing="onEditRecord"
on-delete="onDeleteRecord"
on-update="onUpdateRecord"
></task-element>
</template>
</template>
<script src="list-view.js"></script>
and the _renderRepeat function:
_renderRepeat: function () {
this.paperCard = Polymer.dom(this.root).querySelectorAll('task-element');
this.animationConfig['entry'].push({
name: 'cascaded-animation',
animation: 'transform-animation',
transformFrom: 'translateY(100vh)',
nodes: this.paperCard
});
this.playAnimation('entry');
}
the task-element has "Polymer.NeonAnimationRunnerBehavior" behavior.
I think something must be inherited from base paper-element which i don't know what it is.
Thank you

Polymer Check for Insertion Points

I'm starting to learn Polymer 1.0 and I couldn't figure out how to programatically search for insertion points. I realize I could wrap a <div> around the <content> tag and check if that <div> has children or not, but that requires rendering a <div> for every element, which seems wasteful. Is there a way, with JavaScript, to check if any insertion points have been loaded? Ideally, I'd have a function thereAreInsertionPoints which would determine whether or not the <p> tag would render. My Polymer code looks like this:
<template>
<h1>{{title}}</h1>
<p>{{body}}</p>
<content id="content"></content>
<p if="{{thereAreInsertionPoints()}}">There are insertion points!</p>
</template>
<script>
Polymer({
is: "post-content",
properties: {
title: String,
body: String
},
thereAreInsertionPoints: function(){
//determine whether or not we have insertion points
}
});
</script>
There are various Polymer APIs for working with the DOM including Content APIs.
Content APIs:
Polymer.dom(contentElement).getDistributedNodes()
Polymer.dom(node).getDestinationInsertionPoints()
These APIs can be used in various ways to check for distributed nodes and insertion points. I have created a working implementation that shows the post-content element with additional methods to check for distributed nodes and destination insertion points.
<script src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import"
href="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html">
<dom-module id="post-content">
<template>
<h1>{{title}}</h1>
<p>{{body}}</p>
<content></content>
<template is="dom-if" if="{{destinationInsertionPointsExist()}}">
<p>Destination insertion point(s) exist.</p>
</template>
<template is="dom-if" if="{{distributedNodesExist()}}">
<p>Distributed node(s) exist.</p>
</template>
</template>
<script>
Polymer({
is: "post-content",
properties: {
title: String,
body: String
},
destinationInsertionPointsExist: function () {
var distributedNodes = Polymer.dom(this).childNodes;
var countDestinationInsertionPoints = 0;
distributedNodes.forEach(function (distributedNode) {
var distributedNodeHasDestinationInsertionPoints = Polymer.dom(distributedNode).getDestinationInsertionPoints().length > 0 ? true : false;
if (distributedNodeHasDestinationInsertionPoints) {
countDestinationInsertionPoints++;
}
});
return countDestinationInsertionPoints > 0 ? true : false;
},
distributedNodesExist: function () {
var contentNodes = Polymer.dom(this.root).querySelectorAll("content");
var countDistributedNodes = 0;
contentNodes.forEach(function(contentNode) {
var contentNodehasDistributedNodes = Polymer.dom(contentNode).getDistributedNodes().length > 0 ? true : false;
if (contentNodehasDistributedNodes) {
countDistributedNodes++;
}
});
return countDistributedNodes > 0 ? true : false;
}
});
</script>
</dom-module>
<post-content title="This is the title" body="This is the body">
<p>This is distributed content</p>
</post-content>
A few notes about the code:
I made a lot of the variable names and ternary checks very verbose for clarity in this answer. Changes could be made to simplify the code.
For example:
var distributedNodeHasDestinationInsertionPoints = Polymer.dom(distributedNode).getDestinationInsertionPoints().length > 0 ? true : false;
could become something like
var hasInsertionPoints = Polymer.dom(distributedNode).getDestinationInsertionPoints().length
Use the new (Polymer 1.0) dom-if conditional template.
<p if="{{thereAreInsertionPoints()}}">There are insertion points!</p>
becomes
<template is="dom-if" if="{{destinationInsertionPointsExist()}}">
<p>Destination insertion point(s) exist.</p>
</template>
I would recommend stepping through the destinationInsertionPointsExist and distributedNodesExist methods to insure that you fully understand what is actually being checked. You may need to modify these methods to suit your particular needs and requirements.
For example, even if you have a single space between the post-content element start and end tag both of these methods will return true.
<post-content title="This is the title" body="This is the body"> </post-content>

Read content of nested template

How can I get JS access to .content of nested <template>?
I am trying to extend <template> with my imported-template element (which fetches template content from external file) and I would like to implement <imported-content> in similar manner to native <content>. To do so, I simply try
this.content.querySelector("imported-content")
but it occurred, that for nested template this.content is empty.
<script>
(function() {
var XHTMLPrototype = Object.create((HTMLTemplateElement || HTMLElement).prototype);
XHTMLPrototype.attachedCallback = function() {
//..
var distributeHere = this.content.querySelector("imported-content");
var importedContent = document.createElement("span");
importedContent.innerHTML = "Imported content";
distributeHere.parentNode.replaceChild(importedContent, distributeHere);
}
document.register('imported-template', {
prototype: XHTMLPrototype,
extends: "template"
});
})();
</script>
<template id="fails" bind>
<ul>
<template is="imported-template" bind="{{ appdata }}">
<li>
<imported-content></imported-content>
</li>
</template>
</ul>
</template>
JSFiddle here
I am not sure if it is a bug, a design issue, or just template shim limitation.
I thought that maybe I am checking it in wrong life-cycle callback, so I tried MutationObserver fiddle here, but mutation does not occur as well.
I changed your selector to this.content.querySelector("[is='imported-content']"). Is this what your trying to do?

Meteor: Hide or remove element? What is the best way

I am quite new with Meteor but have really been enjoying it and this is my first reactive app that I am building.
I would like to know a way that I can remove the .main element when the user clicks or maybe a better way would be to remove the existing template (with main content) and then replace with another meteor template? Something like this would be simple and straightforward in html/js app (user clicks-> remove el from dom) but here it is not all that clear.
I am just looking to learn and for some insight on best practice.
//gallery.html
<template name="gallery">
<div class="main">First run info.... Only on first visit should user see this info.</div>
<div id="gallery">
<img src="{{selectedPhoto.url}}">
</div>
</template>
//gallery.js
firstRun = true;
Template.gallery.events({
'click .main' : function(){
$(".main").fadeOut();
firstRun = false;
}
})
if (Meteor.isClient) {
function showSelectedPhoto(photo){
var container = $('#gallery');
container.fadeOut(1000, function(){
Session.set('selectedPhoto', photo);
Template.gallery.rendered = function(){
var $gallery = $(this.lastNode);
if(!firstRun){
$(".main").css({display:"none"});
console.log("not");
}
setTimeout(function(){
$gallery.fadeIn(1000);
}, 1000)
}
});
}
Deps.autorun(function(){
selectedPhoto = Photos.findOne({active : true});
showSelectedPhoto(selectedPhoto);
});
Meteor.setInterval(function(){
selectedPhoto = Session.get('selectedPhoto');
//some selections happen here for getting photos.
Photos.update({_id: selectedPhoto._id}, { $set: { active: false } });
Photos.update({_id: newPhoto._id}, { $set: { active: true } });
}, 10000 );
}
If you want to hide or show an element conditionaly you should use the reactive behavior of Meteor: Add a condition to your template:
<template name="gallery">
{{#if isFirstRun}}
<div class="main">First run info.... Only on first visit should user see this info.</div>
{{/if}}
<div id="gallery">
<img src="{{selectedPhoto.url}}">
</div>
</template>
then add a helper to your template:
Template.gallery.isFirstRun = function(){
// because the Session variable will most probably be undefined the first time
return !Session.get("hasRun");
}
and change the action on click:
Template.gallery.events({
'click .main' : function(){
$(".main").fadeOut();
Session.set("hasRun", true);
}
})
you still get to fade out the element but then instead of hiding it or removing it and having it come back on the next render you ensure that it will never come back.
the render is triggered by changing the Sessionvariable, which is reactive.
I think using conditional templates is a better approach,
{{#if firstRun }}
<div class="main">First run info.... Only on first visit should user see this info.</div>
{{else}}
gallery ...
{{/if}}
You'll have to make firstRun a session variable, so that it'll trigger DOM updates.
Meteor is reactive. You don't need to write the logic for redrawing the DOM when the data changes. Just write the code that when X button is clicked, Y is removed from the database. That's it; you don't need to trouble yourself with any interface/DOM changes or template removal/redrawing or any of that. Whenever the data that underpins a template changes, Meteor automatically rerenders the template with the updated data. This is Meteor’s core feature.

Categories