I've written a function (Polymer 1.2.0) to return an auth header for iron-ajax, but no matter what I try, I get the message
[dom-bind::_annotatedComputationEffect]: compute methodmakeheadersnot defined
In addition to this code, I've also tried the `Polymer({is: 'dom-bind'} ... blah:fn()' way of binding the fn.
What am I doing wrong? Here's the relevant chunk of the code:
<div id="futuretweets" style="height: 400px">
<template is="dom-bind" id="big-temp">
<script>
document.querySelector('template[is=dom-bind]').makeheaders = function () {
var obj = {};
obj.Authorization = "Bearer " + localStorage.getItem('userToken');
return obj;
};
</script>
<iron-localstorage name="auth" value="{{localtoken}}"></iron-localstorage>
<iron-ajax url="api/twitter/v1/private/gettweets" last-response="{{data}}" auto
headers="{{makeheaders()}}"
handle-as="json">
</iron-ajax>
<iron-list items="[[data.futuretweets]]" as="item">
<template id="tweet-item">
<form is="iron-form" id="tweetform" method="post" action="api/twitter/v1/private/updatetweet"
headers="{{makeheaders()}}" contentType="application/json">
<div class="card layout horizontal center">
<paper-textarea label="Tweet">[[item.text]]</paper-textarea>
<p>datetime: [[item.datetime]]</p>
</div>
<paper-button>Save</paper-button>
</form>
</template>
</iron-list>
</template>
<div id="tweeteditor">
</div>
</div>
Move the script outside of the template element. Templates are static. What happens in your code is that you are declaring the dom-bind's property after it was stamped to the DOM.
Related
New to vuejs. I am trying to write javascript directly in the vue file. Below is the code. I keep getting the following errors...
compiled with problems
70:18 error 'openpopup' is defined but never used no-unused-vars
73:18 error 'closepopup' is defined but never used no-unused-vars
Html with script:
<template>
<div class="customers-page">
<h2>Customers</h2>
<button type="add" class="add-button" onclick="openpopup()">Add</button>
<div class="popup" id="popup">
<h3>Input the following information</h3>
<button type="add-customer" class="submit-customer-button" onclick="closepopup()">Submit</button>
</div>
</div>
</template>
<script type="application/javascript" >
let popup = document.getElementById("popup");
function openpopup(){
popup.classList.add("open-popup")
}
function closepopup(){
popup.classList.remove("open-popup")
}
</script>
The very purpose to use Vue is to leverage its features for handling this type of logic reactively, Following is the snippet which can be used(vue 3 options api)
<template>
<div class="customers-page">
<h2>Customers</h2>
<button type="add" class="add-button" #click="openpopup">Add</button>
<!-- onclick="openpopup()" -->
<div class="popup" :class="popupToggle ? 'open-popup' : ''">
<h3>Input the following information</h3>
<button type="add-customer" class="submit-customer-button" #click="closepopup">Submit</button>
<!-- onclick="closepopup()" -->
</div>
</div>
</template>
<script>
export default {
data() {
return {
popupToggle: false,
};
},
methods: {
openpopup() {
this.popupToggle = true;
},
closepopup() {
this.popupToggle = false;
},
},
};
</script>
Here the popup view is maintained by a state variable popupToggle, if you want to use something similar to id then you should go through refs here
When you use frameworks like Vue / React etc, using the native DOM is discourage (basically those .getElementById, .classlist.add or similar). One main reason is security, anyone can go to inspect and do DOM manipulations.
If you want to avoid the Options API boilerplate, you can use Composition API, which is similar to what you are doing.
Besides, if you are using conditional rendering, v-if is recommended instead of class binding, because the elements are not rendered if it is false.
<template>
<div class="customers-page">
<h2>Customers</h2>
<button type="add" class="add-button" #click="openPopup()">Add</button>
<div v-if="isShowPopup" class="popup">
<h3>Input the following information</h3>
<button type="add-customer" class="submit-customer-button" #click="closePopup()">Submit</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const isShowPopup = ref(false)// acts similar to options api data block
// here I am using arrow functions
const openPopup = () => {
isShowPopup.value = true // in composition API, instead of using this., you use .value
}
const closePopup = () => {
isShowPopup.value = false
}
</script>
I've been trying to execute a method when a image has fully loaded, but it simply throws an error that my function doesn't exists:
Uncaught ReferenceError: imageLoaded is not defined
at HTMLImageElement.onload (projetos:1)
Here's my code:
<template>
<div class="card">
<h2>{{projeto.nome}}</h2>
<div class="row">
<div class="col-sm-10 col-sm-offset-1" id="img-container">
<img :src="projeto.foto" :alt="projeto.nome" onload="imageLoaded()">
<div class="row" id="info">
<div class="col-xs-6">Conclusão: {{projeto.duracao}}</div>
<div class="col-xs-6">Projeto realizado em {{projeto.ano}}</div>
<br><br>
<p>{{projeto.descricao}}</p>
</div>
</div>
</div>
</div>
</template>
<script>
import { eventBus } from "../../main";
export default {
props: ["projeto"],
methods: {
imageLoaded() { // the function i want to execute
eventBus.loading(false);
}
}
};
</script>
I've tried using :load="" (wich i discovered that doesn't exists) and placing a function outside my export default scope. Since my images are in a v-for i think onload is the best way of achieving this.
So is there a better way? How can i do this? Is there a directive i can use? Am i doing something wrong?
Use the v-on directive or the shorthand # for listening for DOM events like you would do for example with #click="" - so #load="imageLoaded()" should work.
In my mustache template I do have something like:
<div {{attr}}="{{attrVal}}"></div>
Rendering this using
Mustache.render(template, {attr : 'data-test', attrVal : 'test'})
does produce
<div ="test"></div>
I expect to get something like
<div data-test="test"></div>
Isn't it possible to render attribute name inside of a tag using Mustache?
UPDATE
I figured out the problem. I define my HTML Mustache Templates inside custom <template> tags in my document. For example:
<template id='myTemplate'>
<div {{dataAttr}}="{{dataAttrValue}}"></div>
</template>
When getting the template using document.querySelector("#myTemplate").innerHTML the browser does convert the {{dataAttr}} to {{dataattr}} because attributes are case insensitiv. So calling
Mustache.render(
document.querySelector("#myTemplate").innerHTML,
{ dataAttr : 'data-attr', dataAttrValue : 'test'}
);
Results in
<div ="test"></div>
Hope this code snippet will help you..
var template = document.querySelector("#template").innerHTML;
//Mustache.parse(template); // optional, speeds up future uses
var rendered = Mustache.render(template, {
attr: "data-test",
attrVal: "test"
});
document.querySelector("#target").innerHTML = rendered;
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.2.1/mustache.js"></script>
<body>
<div id="target">Loading...</div>
<template id="template" >
<textarea style="width:300px">
<div {{attr}}="{{attrVal}}"></div>
</textarea>
</template>
</body>
I head the same problem Try the single [']:
<template id='myTemplate'>
<div {{dataAttr}}='{{dataAttrValue}}'></div>
</template>
.....
You can also try using to_html method for the expected output.
const HTML = Mustache.to_html(template, {attr : 'data-test', attrVal : 'test'});
document.getElementById("myTemplate").innerHTML = HTML;
const template = `
<div {{attr}}="{{attrVal}}">
</div>
`
const HTML = Mustache.to_html(template, {attr : 'data-test', attrVal : 'test'});
document.getElementById("myTemplate").innerHTML = HTML;
console.log(document.getElementById("myTemplate").innerHTML);
<html>
<head>
</head>
<body>
<template id='myTemplate'>
</template>
<div id="display-output"></div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.1.0/mustache.min.js"></script>
</body>
</html>
element that shows events. The events come from a JSON file and are loaded by core-ajax
It has a detail and a non-detail template, which can be toggled.
At first the non Detail template is loaded, then you can toggle additional information and the seccond template is loaded.
<template if="{{showDetail}}" >
<core-ajax auto
response="{{data}}"
on-core-response="{{ajaxHandler}}"
url ="http://localhost:8080/myevents/getDetailEvent={{nummer}}";
handleAs="json"></core-ajax>
<div class="showbox" >
<h2 id= "title"> </h2>
<p><b>Start:</b> {{data.startDate }}</p>
<p><b>Ende:</b> {{data.endDate }}</p>
<p id = "place"></p> </br>
<p id = "description"></p> </br>
<p id = "manager"></p> </br>
<button on-tap="{{toggleView}}">Less</button>
</div>
</template>
Non-Detail Template
<template if="{{!showDetail}}" >
<core-ajax auto
response="{{data}}"
on-core-response="{{ajaxHandler}}"
url ="http://localhost:8080/myevents/getEvent={{number}}";
handleAs="json"></core-ajax>
<div class="showbox" >
<h2 id= "title"> </h2>
<p><b>Start:</b> {{data.startDate}}</p>
<p id = "description"></p> </br>
<button on-tap="{{toggleView}}">More</button>
</div>
</template>
In my JSON I have a lot of HTML Tags thats why I use injectBoundHTML() to output them on my Screen. Here is my dataChanged method, which gets called when the component is loaded the first time, or I click the toggle Button:
dataChanged : function() {
if (this.data){
if(this.showDetail) {
this.injectBoundHTML(this.data.titleDe, this.$.titleDe);
this.injectBoundHTML(this.data.description, this.$.description);
this.injectBoundHTML(this.data.manager, this.$.manager);
} else {
this.injectBoundHTML(this.data.titleDe, this.$.titleDe);
this.injectBoundHTML(this.data.description, this.$.description);
}
}
}
When the component is loaded the first time, injectBoundHTML() is working and injects all of the content coming from the json. When I push the toggle Button no injection takes place! If I add the JSON content in the dataChanged MEthod without injection, it works!
What am I doing wrong?
On my polymer-based website I created a custom element in that I am loading data via ajax. Depending on the current state of data-loading i created some <template if="{{}}"> elements to display the right content. It looks something this way:
<polymer-element name="modules-item" attributes="moduleID categories">
<template >
<service-get-module module="{{module}}" moduleID="{{moduleID}}"></service-get-module>
<paper-shadow z="1">
<core-toolbar>
<span flex hero-id="title" hero itemprop="name">{{module.title}}</span>
</core-toolbar>
</paper-shadow>
<paper-progress id="moduleLoadingProgress"></paper-progress>
<template if="{{moduleID == null}}">
<p>Modul not available</p>
</template>
<template if="{{moduleID != null && module == null}}">
<p>Module is loading...</p>
</template>
<template if="{{moduleID != null && module != null}}">
<div id="moduleContainer">
<!-- Content //-->
</div>
<template>
</template>
<script>
Polymer({
module: null,
moduleID: null,
ready: function(){
console.log(this.$.moduleContainer);
}
</script>
</polymer-element>
That works great, but if I try to access the <div id="moduleContainer"> I don't get it... I just read so many posts but did not get any solution. May anybode help me? :)
Here is the link to the live website: http://www.test.gruppenstunde.eu/
UPDATE
After working a little longer with polymer I found out, that it's easier to use the hidden?-Attribute, to casual hide content. Example:
<div hidden?="{{moduleID != null}}">Module not available</div>
You can't access elements within <template if="{{..}}"> or <template repeat="{{..}}"> (dynamically created) using the $ accessor. You need to use querySelector(...) and you can the field only when the if expression evaluates to true (the element is actually created/shown)
to get access to that element you can put that template in a div and give the div a id.
<div id="mod">
<template if="{{moduleID != null && module != null}}">
<div id="moduleContainer">
<!-- Content //-->
</div>
<template>
</div>
then you can
var el = this.$.mod.querySelector("#moduleContainer");