I'm using d3 for graphing, and I'm trying to create an svg object, to add to the DOM later.
I used to have
var svg = d3.select(el).append("svg");
var graph = svg.append("g")
...etc...
and for reasons I won't go into, I wanted to create the svg element before appending it to the DOM.
So I did
var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg'))
var graph = svg.append("g")
...etc...
, which works, and while debugging, I can see that svg is a 1-element array, with the children nicely attached.
The problem comes at the append step:
d3.select(el).append(svg);
There, I get an error Error: Failed to execute 'createElementNS' on 'Document': The qualified name provided ('[object SVGSVGElement]') contains the invalid name-start character '['. I've taken a look here: How to create "svg" object without appending it? but it seems that's exactly how they suggest it.
Any idea why this is so? I've tried appending svg[0], but no luck either. It seems append() only takes strings as an argument.
edit: the d3 reference at https://github.com/mbostock/d3/wiki/Selections#append states
selection.append(name)
... ... ...
"The name may be specified either as a constant string or as a function that returns the DOM element to append."
Consequently I've tried
d3.select(el).append(function(){return svg;});
but that fails with a Error: Failed to execute 'appendChild' on 'Node': The new child element is null.
If svg is a selection, svg.node() returns the DOM element, e.g.:
d3.select(el).append(function(){return svg.node();});
(Mind you, I'm not certain that svg in your case is a true selection, but you could give it a try.)
You might be better off using the regular element.appendChild function for this.
You can get a reference to your parent element using d3.select(el).node() then, you can call .appendChild on that, passing in svg.node() as the element to append.
So, all together:
d3.select(el).node().appendChild(svg.node());
Related
I have a table in which I want to extract the text of the active item. I do this with the following code:
var addedWorkout = $("#custDropDownMenuA").find(".dropdown-item.active");
console.log(addedWorkout);
addedWorkout = addedWorkout.textContent;
console.log(addedWorkout);
The problem is that I keep getting undefined. I checked the console and it indeed finds the element I want without fail.
I am relatively new to Javascript, but after over an hour of Googling I could not find the issue and I don't understand why. I know that I can get the text element if I hardcore it using the following line:
document.querySelector("#selectiona1").textContent
but not with:
$("#selectiona1").textContent
What is the difference between these 2? I read that textContent is part of the DOM, to my understanding it relates to objects and according to my console i think it is an object. I made some crazy attempts like putting the object I got into the querySelector, but nothing works.
With this line:
var addedWorkout = $("#custDropDownMenuA").find(".dropdown-item.active");
you're using jQuery to select the .dropdown-item.active inside #custDropDownMenuA, and when you select with jQuery, you get a jQuery object in response. So, addedWorkout is a jQuery object, and jQuery objects generally do not have the same properties/methods as standard HTMLElements. (querySelector is the vanilla Javascript method to retrieve an element)
Either select the [0]th item in the jQuery collection to get to the first matching element:
var addedWorkout = $("#custDropDownMenuA").find(".dropdown-item.active")[0];
Or use the jQuery method to get the text of the first matching element, which is .text():
var addedWorkoutText = addedWorkout.text();
(note the use of a new variable - you will likely find it easier to read and debug code when you create new variables rather than reassigning old ones, when possible)
Your var 'addedWorkout' is a Jquery object, not a html element.
To show the text use:
addedWorkout.text();
Alternatively, you can change the 'addedWorkout' to a html element by adding the index [0], like this:
addedWorkout[0].textContent;
I'm learning Javascript right now, and attempting to change the text title of a particular tab. It's actually part of a larger Shiny dashboard project, but I want to add some custom functionality to a few tabs. Below are the tabs in question:
Simple enough. I first access my tabs in my Javascript file:
var tabScrub2 = $(document).find('[data-value="scrubTab2"]');
console.log(tabScrub2);
When I use Firefox's developer console, I see that the tab is an object:
Moreover, it looks like I need to change the innerText property of 0, whatever this is, since that corresponds to the title of my tab (the innerText of 1 corresponds to the text inside scrubTab2). However, I'm not familiar with the actual object type being returned here:
Simply put, how the heck do I access and manipulate properties from this? And am I actually accessing an array? When I type in
var scrub2 = tabScrub2["1"];
console.log(scrub2);
I get an HTML element. I'm seen the a element in CSS and jQuery, but am not super familiar with how to manipulate its properties programmatically? How do I go about accessing and manipulating the innerText properties of this via Javascript? For instance, how would I hide scrubTab2, or change its title to something else?
The first object you're seeing is jQuery's wrapper around the real DOM elements. It's not an actual array, but it does contain all of the elements that matched your query under zero-indexed properties (e.g. "0" and "1") which allows you to access to them via an array-like API (e.g. tabScrub[1]).
Your method of grabbing a node using tabScrub2["1"] is correct (see this question in the jQuery FAQ). It's more likely to see that done with a numeric key though (i.e. tabScrub[1]) because that matches the way you would access an element in a normal array.
As far as manipulating properties of the DOM node, the DOM's API is notoriously inconsistent and quirky (hence the need for things like jQuery in the first place). However, for your use case you can just assign a string to the innerText property directly (e.g. tagScrub2[1].innerText = "Tab title"). MDN is a great resource if you're looking for reference material on other parts of the DOM.
A side note: if you're looking for a specific element you should use a query that will only match that element. It's generally a bad sign if you're grabbing extra elements and then accessing the element you want at a key other than 0. If you're doing this then your code depends on other (potentially unrelated) nodes in the DOM existing before your node, and if/when you change those nodes your original code will break.
Just use jQuery eq method to get the relevant object index from the array.
For an example
//Query and get first element.
var tabScrub2 = $(document).find('[data-value="scrubTab2"]:eq(0)');
//Hide
tabScrub2.hide();
//Change title
tabScrub2.attr("title", "New Title Text");
Lean more about jQuery eq here.
https://api.jquery.com/eq/
Since you use jquery selectors tabScrub2[0] returns the native DOM element instead of another jQuery object. Therefore the hide function won't work in that object since the native DOM element doesn't implement such type of functionality for an element. That's why you have to use jQuery pseudo selector as above. Because hide will only work with a jQuery object.
I'm building a custom visual for Power BI, written in TypeScript. In my class' constructor I write this.svg = d3.select(this.target).append("svg").attr("id", "svg"); (this.target just holds a standard HTML element, it's not important for the question).
My question is ,using this.svg, how can I obtain just the raw SVG element? From Googling it seems I should be able to use this.svg.node(), but there must be something subtle going on that makes this different to the "true" element...
When I run console.log(this.svg.node()), its output appears exactly the same as console.log(document.getElementById("svg")) in Chrome's developer window, so that's fine.
However, using the expression this.svg.node().getBoundingClientRect() causes my TypeScript to not compile because of the error Property 'getBoundingClientRect' does not exist on type 'Node', whereas document.getElementById("svg").getBoundingClientRect() returns the correct value.
How do I just get the true, raw DOM element that this.svg refers to?
I'm using d3 v3.
.node() is returning the real element, the problem here is that in other situations .node() can return other types of objects than just Elements, so the typescript compiler can't know it'll definitely have the getBoundingClientRect() function.
The solution is to cast the object as type Element:
var svgElement = this.svg.node() as Element;
var boundingRect = svgElement.getBoundingClientRect();
I'm trying to add a class and ID to specific Two.js objects in this project: http://itpblog.evejweinberg.com/Homework/Open/ (click a few times to play)
If I console.log the word 'background' I see that these are two.js objects but I can't seem to use css or jquery to add a class/ID to them.
Any help is appreciated!
I even tried adding it to the whole project but that did not work:
$(document.body).addClass("dropshadow");
two.js entities are not DOM elements themselves, but each Scene, Group, or Polygon contains at least one reference to the DOM element that gets drawn when the entity is changed. To reference various DOM elements use the following syntaxes:
// Initialize two.js and attach to a dom element referenced by `canvas`
var two = new Two(params).appendTo(canvas);
// Two.Scene
var my_scene = two.renderer.domElement;
// Two.Group
var my_group = document.getElementById(two.scene.id);
// Two.Polygon — requires knowing the ID by means of your custom app logic.
var my_poly = document.getElementById(my_poly_html_id);
my_poly.classList.add('my-class');
Here's a screenshot showing all three commands in an actual app along with the outcome of each, with one additional command add a class to the shape that was targeted. The syntax of the last command differs but I omitted the var statements so that the console would display the result instead of outputting undefined.
If you'd like to create custom HTML IDs for individual shapes, use the .id setter before the initial render of your shape. Since most of this code is just setup, I offer a practical example on one of my own projects. In that snippet, a shape variable holds a new instance of Two.Polygon so calling shape.id = 'something-unique' before calling two.update() to draw the shape for the first time results in a DOM element with a custom HTML ID. Here is an incomplete block of setup code showing how to set the ID:
// Create new shape
var shape = two.makeRectangle(START_X, START_Y, START_WIDTH, START_HEIGHT);
// Set custom ID
shape.id = 'shape-' + Math.random(10000000);
// Draw shape for first time.
two.update();
My code is like this
var tariffdate = PriceSheet.children('TariffEffDate')[1].text;
Where I expect to get data inside TariffEffDate tag. But it gives me undefined instead.
I can Get <TariffEffDate>1999-01-01T00:00:00</TariffEffDate> as a result for code
console.log(PriceSheet.children('TariffEffDate')[1])
But when I add .text to get data inside this node it is giving me undefined.
Can anyone point out what I am doing wrong here?
You need to use Node.nodeValue instead of .text.
.children('TariffEffDate')[1] will give you a HTMLElement that inherits Node, but it won't give you a leaf node, meaning that this HTMLElement might have multiple children. This is why you cannot get the value of (technically) multiple child-nodes. You can access the first node by calling Node.firstChild.
Essentially, you want your final code to be:
var tariffdate = PriceSheet.children('TariffEffDate')[1].firstChild.nodeValue;