Polymer - Get data-bound attribute value in repeating template - javascript

I'm having a bit of an issue here. I had a small amount of success with event.target.templateInstance.model.thing syntax to get the value of attributes from within a repeating template but I keep getting back undefined from this bit of code I have here:
downloadFunction: function (e) {
console.log("dl function clicked");
//get particular id of thing
var fu = e.target.templateInstance.model.s.soundId;
console.log(fu);
//^ returns "TypeError: Cannot read property 'soundId' of undefined"
}
And my repeating template is here:
<div layout horizontal wrap center center-justified>
<template repeat="{{s in carddata}}">
<sound-card image="{{s.imgurl}}"
quotetext="{{s.quote}}"
soundsrc="{{s.soundurl}}"
soundref="{{s.soundId}}"
downloadfunction="{{downloadFunction}}">
</sound-card>
</template>
</div>
Where carddata is just an array with my data in it. All of the values are generated fine so I know it's not an issue with my array. I'm just confused how exactly I'm supposed to target someting from within the repeating template? Am I calling it at the wrong time? Or am I messing up the syntax of the templateInstance bit?
If it matters, I'm trying to get it to work in an Android 4.4 webView using Apache Cordova. 4.4 webView doesn't appear to enjoy the shadowDOM terribly much.
Thanks!
edit: After some jiggery pokery with console logs, it appears that the sender value is referring to the div that I apply the on-click="{{downloadFunction}} to. Here's the template that I am repeating, if this provides any insight.
<div class="soundcard-container" vertical layout>
//can't target this one either on WebView 4.4, works on ChromeOS
<img src="{{image}}" on-tap="{{playAudio}}">
<div class="soundcard-bottom-container" horizontal layout center justified>
<span>{{quotetext}}</span>
//I have an 'a' tag for desktop browsers and the div tag is targeting my Android/iOS
//apps that I am exporting as a webView to using Apache Cordova. Webonly is hidden
//at the point where I'm trying to get my downloadfunction to work.
//console.log(sender) in my downloadfunction returns this div v
<div on-tap="{{downloadfunction}}" class="mobileonly"></div>
</div>
//just a hidden audio thing for web
<div style="display: none">
<audio id="{{soundref}}" src="{{soundsrc}}" controls preload="auto"></audio>
</div>
</div>
edit2 some console logs..
console.log(sender) and console.log(event.target) are both the same div that has the on-click event for my downloadFunction.. not sure if this should be the case.
console.log(e.target.templateInstance.model) returns my <sound-card> object, I believe like it should(?)
It's just when I add the specific .s.soundId that it's undefined. I'm not sure why it's unable to find it.. Maybe there's another way to get the specific soundId (or s.soundId rather) of that particular <sound-card> object?

I'll bet you want to refer to the "sender" of the event—not e.target. See the part about inSender at https://www.polymer-project.org/0.5/docs/polymer/polymer.html#declarative-event-mapping:
inSender: A reference to the node that declared the handler. This is
often different from inEvent.target (the lowest node that received the
event) and inEvent.currentTarget (the component processing the event),
so Polymer provides it directly.
This might fix it:
downloadFunction: function (e, detail, sender) {
console.log("dl function clicked");
//get particular id of thing
var fu = sender.templateInstance.model.s.soundId;
console.log(fu);
}

Alright I was able to fit this in a different way. I wasn't able to get e.target.templateInstance.model.s.soundId bit to work, so instead on the div that I call the event on (event.target) I gave it an attribute called data-soundid and passed it {{soundref}} from my original template and then where I repeat that template I simply made a function like so:
downloady: function (e) {
console.log(e.target.getAttribute('data-soundurl'));
}
Ta da! Very nice solution. Thanks to Eyal who suggested this to me in a previous question. It works like a charm. :-)

Here is working example of using templateInstance, with included selecting by dynamic ID: Plunk .
As for your code, can't tell why it's not working.
handleEvent: function(e, detail, sender) {
console.log('handleEvent');
console.log(sender.id);
//How to catch full_obj here,
//..as if first item is clicked: full_obj = {"firstName":"John", "lastName":"Doe"}
//console.log(e);
console.log(e.target.templateInstance.model.item.firstName);
//console.log(detail);
//console.log(sender);
this.instance_firstName = e.target.templateInstance.model.item.firstName;
this.instance_lastName = e.target.templateInstance.model.item.lastName;
//Selecting by dynamic ID
var clicked_element = this.shadowRoot.querySelector('#'+this.instance_firstName);
console.log('Selecting');
console.log(clicked_element);
//var second_element = sender.templateInstance.model.querySelector('my-second-element');
//var second_element = this.$.second_element;
}
Edit:
Event handling and data binding Docs

Related

How to add onClick on the component

I am using https://github.com/winhtaikaung/react-tiny-link for displaying some posts from other blogs. I am able to get the previews correctly. I want to capture the views count through onClick() but this module(react-tiny-link) doesn't seems to support the same, please help.
<ReactTinyLink
cardSize="large"
showGraphic={true}
maxLine={0}
minLine={0}
header={""}
description={""}
url={url}
onClick={() => this.handleViewCount(id)} />
I tried adding div around the component but it affects the css.
You can wrap your link with a div and attach your onClick callback on that div instead.
<div onClick={() => this.handleViewCount(id)}>
<ReactTinyLink
cardSize="large"
showGraphic={true}
maxLine={0}
minLine={0}
header={""}
description={""}
url={url}
/>
</div>
Your library - ReactTinyLink does not support onClick attribute.
Since you've tagged javascript - I can give you a small JS hack for the same.
Run the following code at the end of your React Rendering
var cards = document.getElementsByClassName('react_tinylink_card');
linksClicked = [];
for(var i = 0; i<cards.length; i++){
cards[i].onclick = function(){
linksClicked.push(this.href);
}
}
The above code will go through each and every cards and will attach onClick handlers on them, once clicked - the 'this' object will be your anchor tag's element, so I am storing it's href. (you're free to store anything you want)
In the following example - https://winhtaikaung.github.io/react-tiny-link/
I tried the same snippet - and got the following result
Hope this would be a good starting point for what you're trying to achieve.

How to specify a child component to drag its parent component in React?

I'm currently working on a terminal emulator project using React and styled-components. I want to add dragging feature to the terminal. Everything is good, except one thing: I want to click and hold the title bar to drag the terminal, not somewhere else.
Here is my base component: https://codesandbox.io/s/still-http-jxxex
I don't want to use any plugins or libraries because I want to know how it works. So are there any ways to achieve this just by React and javascript? Every comments are appreciated to me.
Well, after reading MDN docs
here is a very simplified version of d&d(the rest is up to you so please read the docs):
link to codesanbox
Bellow is the MDN example my answer based on:
<script>
function dragstart_handler(ev) {
// Add the target element's id to the data transfer object
ev.dataTransfer.setData("application/my-app", ev.target.id);
ev.dataTransfer.dropEffect = "move";
}
function dragover_handler(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = "move"
}
function drop_handler(ev) {
ev.preventDefault();
// Get the id of the target and add the moved element to the target's DOM
const data = ev.dataTransfer.getData("application/my-app");
ev.target.appendChild(document.getElementById(data));
}
</script>
<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">This element is draggable.</p>
<div id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Zone</div>
After days of searching, I found out the problem is that I triggered onMouseDown in window (globally).
In order to do this, I use a function that passed to the child component to update its parent component's states, which is onMouseDown, then got rid of the function in useEffect.
Here's my final solution: https://codesandbox.io/s/admiring-liskov-puu6g

Passing parameter to javascript onclick without using HTML

I can't figure this out. I'm trying to create an onclick handler purely in Javascript.
What I plan to do here is inside this DIV, have a collection of items that I can click on. For now, these items will be numbers from 0 to 9 inclusive. When a number is clicked on, a system message consisting solely of that number should pop-up on the screen. I narrowed my problem down to just the onclick handler definition.
If I use this format:
item[n].onclick=function(n){
handler(n);
}
The handler will fire only when click a number which is correct, but the message that appears is something about mouse event.
If I use this format:
item[n].onclick=function(){
handler(n);
}
The handler will pass a value of -1 which in turn is printed as a message. I think it means "false".
How do I modify this:
item[n].onclick=function(){
handler(n);
}
so that 'n' being used as the handler parameter is the same as the number I click on the screen?
My code is the following:
<div ID="Itemset"></div>
function handler(n){
alert(n);
}
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
collections.appendChild(item[n]);
item[n].onclick=function(n){
handler(n);
}
}
What I'm effectively trying to do if you want to understand it HTML wise is this:
<div ID="Itemset">
<div onclick="handler(0);">0</div>
<div onclick="handler(1);">1</div>
<div onclick="handler(2);">2</div>
<div onclick="handler(3);">3</div>
<div onclick="handler(4);">4</div>
<div onclick="handler(5);">5</div>
<div onclick="handler(6);">6</div>
<div onclick="handler(7);">7</div>
<div onclick="handler(8);">8</div>
<div onclick="handler(9);">9</div>
</div>
Except that I don't want to write out onclick="handler(n);" a million times.
Any advice? and feel free to point to another resource that has the answer I need if there is one.
UPDATE
I'm looking for something compatible with older browsers as well. I'm going to have to not go for the bind function because according to mozilla docs, it works for IE 9+. I'm looking for something that works for IE 7+ as well as other browsers. I might have to go for event listeners if there is no other alternative.
You have a closure issue here (see JavaScript closure inside loops – simple practical example), a simple solution is to use bind to use the current value of n to be a parameter of the handler function
item[n].onclick=handler.bind(item[n],n);
U can use addEventListener and ID for find clicked element...
document.getElementById("Itemset").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was a list item
var value_data = parseInt(e.target.textContent);
if(e.target && value_data > -1) {
alert("Malai test:: "+value_data);
//handler(value_data);
}
});
https://jsfiddle.net/malai/tydfx0az/
I found my answer here: https://bytes.com/topic/javascript/answers/652914-how-pass-parameter-using-dom-onclick-function-event
Instead of:
item[n].onclick=function(n){
handler(n);
}
I have to do:
item[n].onclick=new Function('handler('+n+')');
Funny thing is, the word function needs to be capitalized when making a new instance. It's awkward I have to go this route but it works in IE 7+
One alternative is :
function handler(){
alert(this.id);
}
function myFunction() {
var item=[];
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
item[n].setAttribute("id","itemset"+n);
collections.appendChild(item[n]);
item[n].onclick=handler;
}
}
Insert dynamic ids to the elements and when you click on any element retrieve its id using this.id and do whatever you want to do with that value.
That's all.
Hope this helps.

Dojo destroy MenuItems on DropDownButton

I have the following markup:
<button dojoType="dijit.form.DropDownButton" dojoAttachPoint="labels" label="Labels">
<div dojoType="dijit.Menu" dojoAttachPoint="labelsMenu"></div>
</button>
I am adding MenuItems programatically and it works fine for the first time. But when I want to refresh I get an error: Tried to register widget with id==16 but that id is already registered. I have tried the following code to clear but it's not working:
var labels = dijit.findWidgets(this.labels);
dojo.forEach(labels, function (l) {
l.destroyRecursive();
});
dojo.empty(dojo.byId(this.labels));
I have also try the same thing for labelsMenu to empty it but no luck. Is there any other way to get rid of all children when reloading data or am missing something?
I have solved it and here's what I did:
var menuChildren = dijit.byId(this.labelsMenu).getChildren();
if (menuChildren.length > 0){
dojo.forEach(menuChildren, function(mc){
mc.destroyRecursive();
});
}
In your code you call dojo.empty on the labels. dojo.empty() empties the element in the DOM but keeps the original element. So try calling dojo.empty on the dijit menu instead.
dojo.empty(dojo.byId("labelsMenu"));
For reference, in a fully baseless application, the dom-construct module is used.
require(["dojo/dom-construct"], function(domConstruct){
// Empty node's children byId:
domConstruct.empty("someId");
});

Bizzare Jquery (Mobile) errors when using .find() or selecting a checkbox?

So eh, while making a phone App with phonegap (and using jsconsole.com for debugging) I ran into this bizzare problem when I tried to access a input checkbox and 'check' it with JQuery depending on some scenarios. The problem is a lot more mysterious than that however...
Basic html is as such (inside a jqm-page), which runs from Adnroid Emulator:
<div data-role="controlgroup" data-type="horizontal" id="settings_bar">
<input type="checkbox" name="isAFav" id="isAFav">
<label for="isAFav">Favourite</label>
Delete
</div>
When the page loads to display content I want to adjust the displayed info with a function which looks something like this:
if(isAFav){ // <-local variable from my runtime - it's valid
try{
var fav = $('#settings_bar').find("#isAFav");
fav.attr('checked', 'true');
fav.button('refresh');
}catch(Err){
console.log(err.message());
}
}
The cryptic error that it throws is as such:
Accessing selectionEnd on an input element that cannot have a selection.
The exact same thing happens for a multitude of:
$("#route_settings_bar").children('input');
$('input[name="isAFav"]');
I don't know what the hell is going wrong. I'm using the latest Jquery +mobile (1.9.1 & 1.3.0 respectively).
To add to the confusion, I previously named the form/id of the input as 'fav' and when I ran the corresponding code:
$('input[name="fav"]');
$("#route_settings_bar").children('input[name="fav"]'); //or this
we get this:
To me this looks like JqueryMobile code...what the %&^*? If anyone has any tips or suggestions, please help! Thanks!
P.S. I'm using a different jsconsole ID now.
This is the correct way to check/uncheck checkbox/radio button' using .prop and the refresh it using .checkboxradio('refresh').
if(isAFav){
try{
var fav = $('#settings_bar').find("#isAFav");
fav.prop('checked', true); // here
fav.checkboxradio('refresh'); // here
// OR
// fav.prop('checked', true).checkboxradio('refresh');
}catch(Err){
console.log(err.message());
}
}
Working Demo
Reference

Categories

Resources