How can I manipulate the child node of this element? - javascript

My Chrome Extension needs to change the size of the child node to the following.
Notice how the 'width' is set for the parent DIV...my Chrome Extension did that.
I can show the following element in the console by:
var divContainer2 = $(divContainer)[0];
console.log('Now divContainer is: ', divContainer2);
The element shown in the console by the above (just the start of it, but showing the parent/child relationship):
<div class="v7wOcf ZGnOx" style="margin-top: 80px; width: 1207px;">
<div jscontroller="Zptowf" jsaction="R6jwd:hKrBwc;c96EGd:v8OFqc;QmtCl:.CLIENT;qVp5ue:.CLIENT;AE9bOd:.CLIENT;MmB7ud:.CLIENT;zkkUY:.CLIENT;lyIVcf:.CLIENT;wuANJc:.CLIENT;voP7ud:.CLIENT" jsmodel="PuTOgd IaLzN tZ2gdc dSSknb PTCFbe ephE9e lkzLle OqPTdc nQnzVc VeaFK uArcre" data-without-stream-item-materials="" class="DReKqd" data-submission-id="1" data-view-id="46"><div jscontroller="cs6ocd" jsaction="rcuQ6b:npT2md;KDsQaf:Qp7hp;qFgNIJf-Wvd9Cc Yiql6e iTy5c editable" tabindex="0" role="textbox" aria-required="true" aria-multiline="true"
I want to apply similar styling to the child (the DIV on the second line...with the 'jscontroller').
To make things very explicit I've tried:
var divContainer3 = divContainer2[0];
var divContainer3 = divContainer2.children[0];
And others...
What am I missing? Why can't I grab the childnode of the object I can so clearly push to console and manipulate?
Thank you for any help/direction/guidance...

The issue wasn't syntax...it was dynamic content loading...and so when I was grabbing the childNodes (or trying to) the element didn't exist.
What continues to be confusing for me is that the CONSOLE will show an element called out in console.log even though it didn't exist at the time the particular line of code ran.
So I could SEE the element, and it's nodes/length, in the console but the very next line of code that simply logged the length would come up zero. Because when the length code ran the element didn't really exist.
I added a little 'wait' routine to make sure the thing is there before I try to manipulate it.

Related

How do the document object model values filled by last changed values?

while studying the DOM , i wrote the below script :
console.log(document);//how this will generate the last update id value
var x = document.getElementById("old").getAttribute("id");
var y = document.getElementById("old").setAttribute("id","IDChanged");
console.log(document);
<div id="old">first</div>
both of results are :
<div id="IDChanged"><div>
after running this snippet, i found that both of the results are generating the html document with the same id which is the IDCHANGED , and what I expect is that the first console.log will generate a document with div , its id is old and the second console.log will generate the document with the div id is IDChanged.
SO, HOW to do this work?
You are logging the document object (for some reason that makes no sense), when you are really more interested in the div element. I don't know why you say that you see IDChanged logged twice when neither of your console.log() statements would produce that at all, they would both log the document object, not the div.
If you get rid of your first console.log() and change the last one to:
console.log(x,y);
you will see the results you wanted., but really, forget about document and focus on the div. I think this is what you are looking for to see the id before and after the changes.
// Get a refernece to the div
var x = document.querySelector("div");
// Report the contents of the document before doing anything:
console.log(x);
// Change the ID of the element
x.setAttribute("id","IDChanged");
// Report the contents of the document after DOM manipulation:
console.log(x);
<div id="old">first</div>

getElementsByName not working

Looked up several "Answers" to this problem, but it was mostly just people not treating the result returned by getElementsByName() as a NodeList!
Edit: I am trying to hide/show elements based on an element being clicked. I could hardcode this using document.getElementById and just add one everytime I have an element I want to hide/display. But it would be ideal if I could retrieve all elements named something and just run a loop on them to hide/show. Then I could just tag an element with a name when writing and this loop would work without alteration. Below my code is simply trying to popup an alert with the value for testing purposes. As for now, it consistently breaks with a null error. I am using and designing for internet explorer 9 as this is what the company uses.
Code:
<input type="radio" name="Area" value="Engineering" id="EngineeringCheck" onclick="javascript: ShowContentEngineering();" />Engineering
<script type="text/javascript">
function ShowContentEngineering() {
alert(document.getElementsByName('EngineeringAreas')[0].value)
document.getElementById('InformationBlock').style.display = 'block';
}
</script>
<h5 name="EngineeringAreas" value="luls"> WHAT THE HECK </h5>
Code above breaks saying that the object at getElementsByName('EngineeringAreas')[0] is null. Clearly, right below it, it is not null... Am I confusing getElementsByName('string')[0].value with the value of the element? Or is it retrieving some other value?
Ideally, I'd add other elements later, tag them with "EngineeringAreas" and never have to mess with the hide/show function.
Edit: Here is the error message:
Unhandled exception at line 53, column 9 in http://localhost:57264/Home/Index
0x800a138f - Microsoft JScript runtime error: Unable to get value of the property 'value': object is null or undefined
Here you go... seems:
onclick="javascript: <--- not necessary - just reference the function name
ShowContentEngineering needs to be set in the window context
You're referencing the "value" attribute of an element that doesn't allow value attributes (h5)
I made it work instead grabbing the innerHTML of the h5
Code
<input type="radio" name="Area" value="Engineering" id="EngineeringCheck" onclick="ShowContentEngineering();" />Engineering
<h5 name="EngineeringAreas"> WHAT THE HECK </h5>
<script>
window.ShowContentEngineering = function() {
alert(document.getElementsByName('EngineeringAreas')[0].innerHTML)
document.getElementById('InformationBlock').style.display = 'block';
}
</script>
Here's a working fiddle: https://jsfiddle.net/mu970a8k/
Insert .attributes[1] between .getElementsByName('EngineeringAreas') and .value. The 1 points to the second attribute in the <h5> element named EngineeringAreas, which is value. Placing .value after .attributes[1] should return the value text “luls” in the alert box. The alert code should then be set up like this:
alert(document.getElementsByName('EngineeringAreas')[0].attributes[1].value);
More Info: http://www.w3schools.com/jsref/prop_attr_value.asp

Polymer - Get data-bound attribute value in repeating template

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

Remove and Set an Element's Text

Secrets of the JavaScript Ninja shows how to remove and set an element's text:
HTML
<div id="test">Hey!
<div id="child">delete me</div>
</div>
.
Javascript
var b = document.getElementById("test");
console.log("b before:", b);
while(b.firstChild) {
console.log("removing child:",b.firstChild);
b.removeChild(b.firstChild);
}
console.log("b's value post remove:", b);
b.appendChild(document.createTextNode("Some new text."));
var text = b.textContent || b.innerText;
console.log("text:", text);
Here's the console output:
b before: <div id=​"test">​Some new text.​</div>​
removing child: "Hey!"
removing child: <div id=​"child">​delete me​</div>​
removing child: " "
b's value post remove: <div id=​"test">​Some new text.​</div>​
text: Some new text.
How could b equal Some new text.​ when the HTML is clearly set to Hey!?
Also, why would the b's value post remove: output show up as Some new text even though it hasn't been set yet?
http://jsfiddle.net/X6fYM/
If you're wondering why the console shows you something from later when you logged it before, it's because the console is (partially) a live display of what's in the DOM, not a bunch of strings written out at a moment in time. More about that in this question and its answers.
Basically, if you log an object, the console may treat that as a living display and update it if you change the object. If you log a string, the console will correctly display that as an unchanging thing. So:
var div = document.createElement("div");
console.log("div", div);
div.appendChild(document.createTextNode("foo"));
...can (subject to various conditions) show that the div contains foo, because the console updated the display when we changed it. (Live Example, open the console to see)
If you single-step through the code in a debugger, you can watch the console show one thing, then change it as we change its contents.
Perhaps a little more explanation is in order.
Remember that each item in markup has some sort of element-context. Even text is a Node.
So, there are three Nodes inside of #test at the beginning of your script:
Hey!
<div id="child">delete me</div>
[a blank text node]
This is why you see the output as the while statement works its way through #test's child nodes, removing each one in turn.
Having run your jsFiddle in Firefox, I'm not sure why you're seeing the output you posted:
b's value post remove: <div id=​"test">​Some new text.​</div>​
as it does not display that for me. It only displays that there is a div with the ID of test.
Also, in the beginning, you're creating a pointer to the test node, which is why, when you perform this call:
b.appendChild(document.createTextNode("Some new text."));
b suddenly has content... it never went away, you didn't dispose of the pointer to that object, and so when you test its contents, it displays the new text node that you just added to it.

not able to append html using jQuery (JavaScript)

In this jquery plugin:
http://www.stahs.org.uk/jquery.infinitecarousel.bak
There's this line:
$(obj).append('<div id="textholder'+randID+'" class="textholder" style="position:absolute;bottom:0px;margin-bottom:'+-imgHeight*o.textholderHeight+'px;left:'+$(obj).css('paddingLeft')+'"></div>');
Problem is when it dumps the text node in this div, it aligns to the top of the div. I want text to align to bottom of div. So I decided to create another div within this div:
$(obj).append('<div id="textholder'+randID+'" class="textholder" style="position:absolute;bottom:0px;margin-bottom:'+-imgHeight*o.textholderHeight+'px;left:'+$(obj).css('paddingLeft')+'"></div>');
console.log($('#textholder'+randID));
$('#textholder'+randID).append('<div style="display:table-cell; height: 94.25px; width: 1000px; vertical-align:bottom;"></div>');
The console outputs this:
[div#textholder35196647.textholder]
[div#textholder62315889.textholder]
[div#textholder95654959.textholder]
However, my above append is not working. The nested div never shows up, so when I later do this:
if(t != null)
{
$('#textholder'+randID+' div').html(t).animate({marginBottom:'0px'},500); // Raise textholder
showminmax();
}
No text becomes visible because the nested div never gets created.
So I am extremely confused. If you look at original plugin, this line works:
$('#textholder'+randID+' div').html(t)
How is it able to target the right div here yet when I append to it right after it's created, it doesn't exist, as you guys suggest?
This doesn't work either:
var $texthold = jQuery('<div id="textholder'+randID+'" class="textholder" style="position:absolute;bottom:0px;margin-bottom:'+-imgHeight*o.textholderHeight+'px;left:'+$(obj).css('paddingLeft')+'"></div>');
$(obj).append($texthold);
$texthold.append('<div></div>')
Thanks for response.
It sounds as though perhaps randID has been modified between the $(obj).append... line and your added $('#textholder'+randID)... line. Are you quite sure the value of randID is the same on the two lines?
Are you sure that $(obj) really refers to the element you want to append to? Just in case, you might want to try it the other way round:
$('<div id="textholder'+randID+'" class="textholder" style="position:absolute;'
+'bottom:0px;margin-bottom:'+(-imgHeight*o.textholderHeight)
+'px;left:'+$(obj).css('paddingLeft')+'"></div>'
).appendTo(obj);
It appears this worked:
function showtext(t)
{
if(t != null)
{
if(typeof $('#textholder'+randID).find('div')[0] == 'undefined'){
$('#textholder'+randID).append('<div style="display:table-cell; height: 94.25px; vertical-align:bottom;"></div>');
}
$('#textholder'+randID+' div').html(t);
$('#textholder'+randID).animate({marginBottom:'0px'},500); // Raise textholder
showminmax();
}
}
It's just kind of crazy I had to resort to using typeof to check whether div is declared or not. Why the author of the plugin decided to randomly assign integers as ids of divs is beyond me. By doing that, it appears javascript has difficulty retaining the randomly created id. That's my only explanation for the unusual behavior I could come up with.
Try:
$(obj).after('html');
Documentation is here.

Categories

Resources