Polymer inline conditional, or, how do I display a loading image? - javascript

If I wanted to display a loading image and I was using JQuery to populate my data, I would do something like this:
HTML
<div id="loadthis"><img src="loading.gif"></div>
JS
$('#loadthis').html("Received Data");
However, with Polymer, my template looks like this:
<div id="loadthis">{{receiveddata}}</div>
and I have this property:
Polymer({
is: 'test-loading',
properties: {
receiveddata: {
type: String,
value: ''
}
}
});
I have tried simply putting html in the value for receiveddata but quickly discovered that won't work. I've also tried moustache syntax of {{#if}} etc, but that didn't work at all.
How can I display an image until the receiveddata property is populated?

Based on #a1626's comment mentioning dom-if I came up with this solution:
<div id="loadthis">
<template is="dom-if" if="{{isloading}}">
<img src="loading.gif">
</template>
<template is="dom-if" if="{{!isloading}}">
{{receiveddata}}
</template>
</div>
Then I added an isloading property in my Polymer definition.
Polymer({
is: 'test-loading',
properties: {
receiveddata: {
type: String,
value: ''
},
isloading: {
type: Boolean,
value: true
}
}
});
Now I just set it to false when the data has loaded.
self.isloading = false;

If you want to load local image dynamically, you should load it with full address.
For example, your loading.gif image is under folder /images/loading.gif or /views/loading/loading.gif. Though you can use it like <img src="loading.gif"> statically, once you want to use it dynamically, you should write this.receiveData = '<img src= "/images/loading.gif">'; or this.receiveData = '<img src= "/views/loading/loading.gif">';

Related

VUE: How to make auto import all images from folder?

i trying auto import all images from folder. Under // tested is what i tried:
<template>
<p>classical art</p>
<img v-for="image in images" :key="image" :src="image.url" :alt="image.alt" />
</template>
<script>
export default {
data: function () {
return {
name: "classical-art",
images: [
{ url: require("../assets/images/classical-art/img-00001.jpg"), alt: "prvnĂ­" },
{ url: require("../assets/images/classical-art/img-00002.jpg"), alt: "druhĂ˝" },
],
};
},
};
// tested
const classicalArt = require(`../assets/images/classical-art/.jpg`)
classicalArt.forEach((image) => {
return image;
});
</script>
<style module lang="scss"></style>
Im not good in this things so i will need a help with this. Probably im just stupid, but i cant make it works. If possible, i want it async (lazy) or whatever it is.
----- UPDATE:
I tried something like that, but still nothing, but with require.context i should be able do this probably:
<template>
<p>classical art</p>
<img :src="getImgUrl()" v-bind:alt="req" />
</template>
<script>
export default {
data: function () {
return {
name: "classical-art",
};
},
methods: {
getImgUrl() {
var req = require.context(
"../assets/images/classical-art/",
false,
/\*.jpg$/
);
req.keys().forEach(function (key) {
req(key);
});
},
},
};
</script>
<style module lang="scss"></style>
I want when I add another image to the classical-art folder to create a new tag automatically and display the image without having to edit the code and manually register it
Can anyone help me with this?
For image rendering you must indicate the exact url to every image, so you have to type every url manually in the correct way.
BTW, your idea can be implemented with NodeJS. Node runtime has access to the file system, so url string can be created authomatically for every file.
Vue, unfortunately, has no real access to your files, it means every your component, file or image must be imported manually.

passing event.target.getAttribute() to data in Vue

HTML code:
<img src="images/website/image.svg" alt="" width="150px" height="150px" v-on:click="submitimage($event)">
and want to pass the src url of the image to data passing it through $event to a Vue method.
vue script code:
<script>
export default {
data(){
return {
imgurl: ''
}
},
methods: {
submitimage(event){
var element = event.target;
var id = element.getAttribute('src');
window.console.log(id)
this.imgurl = id
},
},
}
</script>
I also tried:
methods: {
submitimage(event){
this.imgurl = this.event.target.getAttribute('src');
window.console.log(event.target.getAttribute('src'))
},
But it works with window.console.log and shows the correct URL, but if I try it to pass it to data(), its not working.
No error, its just empty or undefined.
What am I missing?
It looks like everything your are doing is correct:
check this stackblitz here: https://stackblitz.com/edit/vue-tu7vzx
So I guess it is really the question how you are trying to access this.imgurl
However, your question does not show enough code to make an educated guess.

Polymer DOM update after viewport refresh

I've been trying to work this out but sofar have been unable to find an answer. My Polymer element loads a base template JSON file, which is then run through a dom-repeat to create a basic HTML page.
Then another JSON text-file is loaded, which completes the various areas of the HTML with a JS function.
Upon button-click form child, a function is run that triggers the loading of another JSON file that adds additional info. This all works fine.
But when I go out of the page and back in it, it has remembered all my settings but does not display things correctly. It displays the translatedText well and the html code is there, but it does not complete the html code for the originalText.
It seems to want to load the last JSON file before the DOM is properly rendered. So I want it to refresh the whole DOM, but how do I do this?
My MWE:
<template>
<iron-ajax
auto
url="basetext.json"
handle-as="json"
last-response="{{baseText}}"></iron-ajax>
<div class="textcontent">
<template is="dom-repeat" items="{{baseText.lines}}" as="line">
<div class="lineblock">
<div class="line" id="line{{line.lineid}}" inner-h-t-m-l="{{line.linetext}}"></div>
<template is="dom-if" if="[[extraShowEnabled]]">
<div class="linepi" id='linepi{{line.lineid}}' inner-h-t-m-l="{{line.linetext}}"></div>
</template>
</div>
</template>
</div>
<template is="dom-if" if="[[extraLoadEnabled]]">
<iron-ajax
auto
url="originaltext.json"
handle-as="json"
last-response="{{originalText}}"></iron-ajax>
</template>
<iron-ajax
auto
url="translatedtext.json"
handle-as="json"
last-response="{{translatedText}}"></iron-ajax>
</template>
<script>
Polymer({
is: 'text-page',
properties: {
translatedText: Object,
originalText: Object,
extraShowEnabled: {
type: Boolean,
value: false
},
extraLoadEnabled: {
type: Boolean,
value: false
},
showViewer: {
type: String,
value: "none"
}
},
observers: [
'setView(showViewer)',
' _computeSegments(translatedText,".line")',
' _computeSegments(originalText,".linepi")'
],
ready: function() {
this.addEventListener('eventFromChild', this.changeView);
},
changeView: function(event) {
this.showViewer = event.detail.selectedView;
},
setView: function(showViewer) {
\\ first some code here to reset all css.
if (showViewer === "none") {
this.extraShowEnabled = false;
this.extraLoadEnabled = false;
}
if (showViewer === "sidebyside") {
this.extraShowEnabled = true;
this.extraLoadEnabled = true;
this._computeSegments(this.originalText,".linepi");
this._addSideBySideCode();
}
},
_computeSegments: function(inputText,linetype) {
if (inputText) {
Array.from(this.querySelectorAll(linetype+" sc-segment")).forEach(item => item.innerHTML = inputText.segments[item.id]);
}
},
_addSideBySideCode: function() {
\\ this function just adds some css.
},
});
</script>
I think You should try to use a compute function result as a dom-repeat item source, something like this:
<template is="dom-repeat" items="{{itmesByParamsCompute(baseText, originalText, translatedText, extraloadEnabled, ...)}}" as="line">
Add as many params as You need to recompute on. Then that compute function should return a valid source anytime at least one of the paras changes.
Also keep in mind, that if any of these params will become undefined that compute function might be ignored completely. Work around for this is making this opposite way - one property which is modified from manny observers, something like this:
properties: {
items_to_use: {
type: Array,
value: []
},
translatedText: {
type: Object,
observer: 'updateItemsToUse'
},
originalText: {
type: Object,
observer: 'updateItemsToUse'
}
},
updateItemsToUse: function (data) {
let updatedArray = this.someMixFixFunction(this.item_to_use, data);
this.set('items_to_use', updatedArray);
},
someMixFixFunction: function (old_array, data_to_apply) {
// do some merging or what ever You need here, for example
let updatedArray = old_array.concat(data_to_apply);
return updatedArray;
}

Data Binding between Polymer Templatizer instance and host

I am trying to use the Polymer templatizer to create a single instance of a template, append it into a div and get data binding to work between the host and this instance but am having difficulty getting this to work.
The most simple example I have tried:
HTML
<dom-module id="test-app">
<paper-input label="host" value="{{test}}"></paper-input>
<template id="template">
<paper-input label="instance" value="{{test}}"></paper-input>
</template>
<div id="placehere"></div>
</dom-module>
JS
Polymer({
is: "test-app",
behaviors: [Polymer.Templatizer],
properties: {
test: {
type: String,
value: 'hello',
notify: true,
},
},
ready: function() {
this.templatize(this.$.template);
var clone = this.stamp({test: this.test});
Polymer.dom(this.$.placehere).appendChild(clone.root);
},
});
The idea above is to create the instance of the template, place it into "placehere" and have the two input text boxes keep in sync.
When the page loads, the instance is created successfully and the value in both textboxes is "hello" but changing either input box does nothing.
The documentation on the polymer page seems a bit lightweight:
https://www.polymer-project.org/1.0/docs/api/Polymer.Templatizer
but it mentions the use of _forwardParentProp and _forwardParentPath. How exactly am I supposed to implement them in my situation?
As you have already figured out, you need to implement some of the Templatizer's methods. Particularly the _forwardParentProp and _forwardParentPath methods.
But before I begin, I must also point out one additional error in your custom elements definition. In your dom-module element, you have the element's contents defined without the template. It is essential to wrap everything within a template element. The fixed version of your custom element would be like this:
<dom-module id="test-app">
<template>
<paper-input label="host" value="{{test}}"></paper-input>
<template id="template">
<paper-input label="instance" value="{{test}}"></paper-input>
</template>
<div id="placehere"></div>
</template>
</dom-module>
As for the implementation of the Templatizer methods, you first need to store the stamped instance. After that, both methods that need implementations are more or less simple one-liners.
Here is the full JavaScript part of the custom element:
Polymer({
is: "test-app",
behaviors: [Polymer.Templatizer],
properties: {
test: {
type: String,
value: 'hello',
notify: true,
},
},
ready: function() {
this.templatize(this.$.template);
var clone = this.stamp({test: this.test});
this.stamped = clone.root.querySelector('*'); // This line is new
Polymer.dom(this.$.placehere).appendChild(clone.root);
},
// This method is new
_forwardParentProp: function(prop, value) {
if (this.stamped) {
this.stamped._templateInstance[prop] = value;
}
},
// This method is new
_forwardParentPath: function(path, value) {
if (this.stamped) {
this.stamped._templateInstance.notifyPath(path, value, true);
}
},
});
Here is a working JSBin demo: http://jsbin.com/saketemehi/1/edit?html,js,output

polymerfire/firebase-query transaction complete event

Very new to Polymer and Polymerfire. I couldn't find an answer here so hoping I can get help here. The basic question I have is "how do I work with the data that polymerfire/firebase-query sends?" Note I'm using polymerfire version 0.9.4, and polymer is version 1.4.0.
I can load my data from Firebase no problem using Firebase query, however some of the values are raw numbers that I need to convert to user friendly information. For example I have time stored in ms that I want to convert to a date, and a numeric field that indicates the "type" of data that is stored and I want to show an icon for it, not just a raw number. I figured my best option would be to use the transactions-complete promise or an observer. Both fire but neither seems to give me access to the data. The Observer's newData is an empty array, and transactions-complete.. well I don't really know what to do with that when the promise fires. Below is my relevant code. I also tried using notify: true, but I seem to not be grasping the concept correctly.
<firebase-query
id="query"
app-name="data"
path="/dataPath"
transactions-complete="transactionCompleted"
data="{{data}}">
</firebase-query>
<template is="dom-repeat" items="{{data}}">
<div class="card">
<div>Title: <span>{{item.title}}</span></div>
<div>Date Created: <span>{{item.dateCreated}})</span></div>
<div>Date Modified: <span>{{item.dateModified}}</span></div>
<div>Status: <span>{{item.status}}</span></div>
</div>
</template>
Polymer({
is: 'my-view1',
properties: {
data: {
notify: true,
type: Object,
observer: 'dataChanged'
}
},
dataChanged: function (newData, oldData) {
console.log(newData[0]);
// do something when the query returns values?
},
transactionCompleted: new Promise(function(resolve, reject) {
// how can I access "data" here?
})`
I wound up going another way entirely, which seemed to be a cleaner approach to what I was doing anyways. I broke it down into separate components. This way when the detail component was loaded, the ready function would allow me to adjust the data before it got displayed:
list.html:
<firebase-query
id="query"
app-name="data"
path="/dataPath"
data="{{data}}">
</firebase-query>
<template is="dom-repeat" items="{{data}}">
<my-details dataItem={{item}}></my-details>
</template>
details.html
<template>
<div id="details">
<paper-card heading="{{item.title}}">
<div class="card-content">
<span id="description">{{item.description}}</span><br/><br/>
<div class="details">Date Created: <span id="dateCreated">{{item.dateCreated}}</span><br/></div>
<div class="details">Last Modified: <span id="dateModified">{{item.dateModified}}</span><br/></div>
<div class="status"><span id="status">{{item.status}}</span><br/></div>
</div>
</paper-card>
</template>
Then in the javascript ready function I can intercept and adjust the data accordingly:
Polymer({
is: 'my-details',
properties: {
item: {
notify: true,
},
},
ready: function() {
this.$.dateModified.textContent = this.getDate(this.item.dateModified);
this.$.dateCreated.textContent = this.getDate(this.item.dateCreated);
this.$.status.textContent = this.getStatus(this.item.status);
},
Try the following changes:
Take out the transactions-completed attribute - it is only relevant when the query is updating data to Firebase
Change the dom-repeat template to get it's items attribute from convertedData - this allows you to do the data conversions to## Heading ## the results of the firebase-query
<firebase-query
id="query"
app-name="data"
path="/dataPath"
data="{{data}}">
</firebase-query>
<template is="dom-repeat" items="{{convertedData}}">
<div class="card">
<div>Title: <span>{{item.title}}</span></div>
<div>Date Created: <span>{{item.dateCreated}})</span></div>
<div>Date Modified: <span>{{item.dateModified}}</span></div>
<div>Status: <span>{{item.status}}</span></div>
</div>
</template>
Add a convertedData property to do your data conversions from data which has the raw data
Change the observer syntax as per the example. This sets up the observer to to observe for changes to deep property values which results in the observer method being fired - see: https://www.polymer-project.org/1.0/docs/devguide/observers#deep-observation
In the observer method you can populate the convertedData object from the data object which should then render the content
Polymer({
is: 'my-view1',
properties: {
data: {
notify: true,
type: Object
},
convertedData: {
notify: true,
type: Object
}
},
// observer syntax to monitor for deep changes on "data"
observers: [
'dataChanged(data.*)'
]
dataChanged: function (newData, oldData) {
console.log(newData);
// convert the "newData" object to the "convertedData" object
}
}

Categories

Resources