Get node inside template if statement - javascript

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");

Related

Vue.js referenced template components stop after first sub component

I'm attempting to create components using Vue, so that I can remove a lot of duplicated HTML in a site I'm working on.
I have a <ym-menucontent> component, which within it will eventually have several other components, conditionally rendered.
While doing this I've hit a wall and so have simplified everything to get to the root of the problem.
When rendering the ym-menucontent component the first sub-component is the only one which gets rendered and I can't work out why or how to get around it...
<template id="menucontent">
<div>
<ym-categories :menuitem="menuitem"/>
<ym-rootmaps :menuitem="menuitem"/>
<p>1: {{menuitem.rootMapsTab}}</p>
<p>2: {{menuitem.exploreTab}}</p>
</div>
</template>
<template id="rootmaps">
<div>Root Maps</div>
</template>
<template id="categories">
<div>Categories</div>
</template>
app.js
Vue.component('ym-menucontent', {
template: '#menucontent',
props: ['menuitem'],
data: function() {
return {
customMenu: window.customMenuJSON
}
}
});
Vue.component('ym-rootmaps', {
template: '#rootmaps',
props: ['menuitem'],
data: function() {
return {
customMenu: window.customMenuJSON,
rootMaps: window.rootAreas
}
}
});
Vue.component('ym-categories', {
template: '#categories',
props: ['menuitem'],
data: function() {
return {
customMenu: window.customMenuJSON,
rootMaps: window.rootAreas
}
}
});
usage...
<div
v-for="mi in customMenu.topLevelMenuItems"
:id="mi.name"
class="page-content tab swiper-slide">
<ym-menucontent :menuitem="mi"/>
</div>
Output
<div>Categories</div>
if I switch around ym-cateogries and ym-rootmaps then the output becomes...
<div>Root Maps</div>
if I remove both then I see...
<p>1: true</p>
<p>2:</p>
I'd expect to see a combination of all of them...
<div>Categories</div>
<div>Root Maps</div>
<p>1: true</p>
<p>2:</p>
This is probably because you're using self-closing components in DOM templates, which is recommended against in the style-guide ..
Unfortunately, HTML doesn’t allow custom elements to be self-closing -
only official “void” elements. That’s why the strategy is only
possible when Vue’s template compiler can reach the template before
the DOM, then serve the DOM spec-compliant HTML.
This should work for you ..
<template id="menucontent">
<div>
<ym-categories :menuitem="menuitem"></ym-categories>
<ym-rootmaps :menuitem="menuitem"></ym-rootmaps>
<p>1: {{menuitem.rootMapsTab}}</p>
<p>2: {{menuitem.exploreTab}}</p>
</div>
</template>
<div
v-for="mi in customMenu.topLevelMenuItems"
:id="mi.name"
class="page-content tab swiper-slide">
<ym-menucontent :menuitem="mi"></ym-menucontent>
</div>

Unable to do Computed Databind

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.

Polymer Load Product Page data from JSON

Working with an e-commerce store application with polymer
I'm loading products array using polymer core-ajax and using core-animated pages to display product thumbnail and product detail page (full view) but I only wanted to load the product details when clicking on each product thumb, How can I do this
Find the HTML
<div id="article-content" >
<template is="auto-binding" id="page-template" >
<core-ajax
id="ajaxpolo" auto
url="./json/products.json"
handleAs="json"
on-core-response="{{handleResponse}}" response="{{headerList}}" on-core-response="{{postsLoaded}}">
</core-ajax>
<core-animated-pages id="fpages" flex selected="{{$.polo_cards.selected}}" on-core-animated-pages-transition-end="{{transitionend}}" transitions="cross-fade-all slide-from-right">
<section vertical layout>
<div id="noscroll" fit hero-p>
<div id="container" flex horizontal wrap around-justified layout cross-fade >
<section on-tap="{{selectView}}" id="polo_cards" >
<template repeat="{{item in headerList}}">
<div class="card" vertical center center-justified layout hero-id="item-{{item.id}}" hero?="{{$.polo_cards.selected === item.id || lastSelected === item.id }}" > <span cross-fade hero-transition style="">{{item.name}}</span></div>
</template>
</section>
</div>
</div>
</section>
<template repeat="{{item in headerList}}">
<section vertical layout>
<div class="view" flex vertical center center-justified layout hero-id="item-{{item.id}}" hero?="{{$.polo_cards.selected === item.id || $.polo_cards.selected === 0}}" >
<core-icon-button class="go_back" icon="{{$.polo_cards.selected != 0 ? 'arrow-back' : 'menu'}}" on-tap="{{goback}}"></core-icon-button>
{{item.name}} <span cross-fade class="view-cont" style="height:1000px; overflow:scroll;"></span></div>
</section>
</template>
</core-animated-pages>
</template>
first you would set the auto attribute of core ajax to false. auto="false" that would stop core-ajax from grabbing data by it's self. then set up a on-tap or on-click attribute on the element you want to be the click / tap handler. on-tap="{{getThem}}" then create the function.
getThem: function () {
this.$.ajaxpolo.go();
}
that should get it. hope it helps.
edit: you will want to grab a few more things with your event.
on the click / tap handler add the id of the item you wish to get to a generic attribute. (stay away from normal attributes. ie id, title and so forth) dataId I will call it.
<div on-tap="{{getThem}}" dataId="{{product_id}}"></div>
then in your function you get a few more things with the event as i said before.
getThem: function (event, detail, sender) {
var id = sender.attributes.dataId.value;
// do something with id
}
i just realized i may have misunderstood when you were talking about php. sorry.

Polymer injectBoundHTML() not working properly

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?

Bind to nested element's function in Polymer.js

I am using Polymer.js, and I am creating an input element with a dropdown suggestions list (like google's search bar).
Basically, I have a core-input, and a core-dropdown, containing a core-menu. I have added two core-a11y-keys to observe arrow keys pressed on the core-input, in order to move the selected item in the core-menu.
I am trying to bind the core-a11y-keys' "on-keys-pressed" event directly to core-menu's selectNext(), and selectPrevious(), but I can't get it to work.
<template>
<link rel="stylesheet" href="suggest-input.css">
<div class="suggest-input-wrapper">
<paper-shadow layout start-justified horizontal center id="feedSearchInput" class="input-shadow">
<input id="searchInput" is="core-input" on-input="{{searchChanged}}" flex placeholder="{{placeholder}}">
<paper-icon-button icon="search" class="feed-search-icon"></paper-icon-button>
<core-dropdown autoFocusDisabled id="suggestionsDropDown" class="suggestions-dropdown">
<core-menu class="suggestions-menu" id="suggestionsMenu">
<template repeat="{{suggestion in suggestionList}}">
<paper-item class="suggestion-item">
<template if="{{suggestion.icon}}">
<core-icon src="{{suggestion.icon}}"></core-icon>
</template>
<template if="{{!suggestion.icon}}">
<core-icon icon="search"></core-icon>
</template>
<h5>{{suggestion.caption}}</h5>
</paper-item>
</template>
</core-menu>
</core-dropdown>
</paper-shadow>
</div>
// First Trial
<core-a11y-keys target="{{searchInput}}" keys="down" on-keys-pressed="{{suggestionsMenu.selectNext}}"></core-a11y-keys>
<core-a11y-keys target="{{searchInput}}" keys="up" on-keys-pressed="{{suggestionsMenu.selectPrevious}}"></core-a11y-keys>
// Second Trial
<core-a11y-keys target="{{searchInput}}" keys="down" on-keys-pressed="{{$.suggestionsMenu.selectNext}}"></core-a11y-keys>
<core-a11y-keys target="{{searchInput}}" keys="up" on-keys-pressed="{{$.suggestionsMenu.selectPrevious}}"></core-a11y-keys>
// Third Trial
<core-a11y-keys target="{{searchInput}}" keys="down" on-keys-pressed="{{this.$.suggestionsMenu.selectNext}}"></core-a11y-keys>
<core-a11y-keys target="{{searchInput}}" keys="up" on-keys-pressed="{{this.$.suggestionsMenu.selectPrevious}}"></core-a11y-keys>
I know I can use custom event handlers, and than call selectNext() and selectedPrevious(), but knowing if it can be done, and how, could help in the future.
Try
target="{{$.searchInput}}"

Categories