How to append multiple child elements to a div in d3.js? - javascript

I'm trying to append two spans to a div using the following code:
d3.select("#breadcrumb")
.append("span")
.attr("class","breadcrumb-link")
.text(d.name)
.append("span")
.text("/");
But this adds elements like:
<div id="breadcrumb">
<span>
<span>
</span>
</span>
</div>
I want to add spans as siblings:
<div id="breadcrumb">
<span>
</span>
<span>
</span>
</div>
I know this can be done by first selecting the div and then using 2 statements for each span. Can I do this in a single chained statement?

d3.js is based on the idea of data-driven documents. That said, typically you'll have data as an array that you gonna join with a selection.
With that in mind you could try a simple hack by joining the selection d3.select("#breadcrumb") with an "artificial" array [1, 2]. This would look like this:
d3.select("#breadcrumb").data([1, 2]).enter().append('span')...
Note, the call of enter().
If you wanna set different class attributes, you could stuff this data into the data array.

Related

Find the relative position-in-DOM of two elements anywhere within an HTML document

I have some HTML that can contain <span>s with a specific class (let's call it marker). These spans can be anywhere in the document under a particular <div> - as direct children, or nested arbitrarily deeply in other nodes.
I then have a particular piece of text selected by the use (so I can use a window.getSelection() call to find the anchor node from Selection.anchorNode). What I want to find out, using Javascript, and jQuery as needed, is the last marker <span> to occur in the documents before that selection. For example:
<div class="container">
<div>
<div>
<span>Some text<span class="marker">Marker 1</span></span>
</div>
<div>
<div>
<span>Foo</span>
<span>THIS IS THE SELECTION ANCHOR NODE</span>
</div>
<span class="marker">Marker 2</span>
</div>
</div><!-- end of container -->
would find Marker 1, even though they are "cousins".
Is there a "standard" approach to determining the relative "linear" positions of an element in the DOM so I can decide if one element is "before" the other?
I am not concerned with the position on the page (x, y), so things like CSS order do not matter.
Things I have thought of, but seem suboptimal:
traversing the parents of each .marker (and the selection span) using [closest()][2] and constructing some kind of lexicographic ordering of nodes, which seems expensive and error-prone
traversing parents of .markers and storing lists of the spans found within
Both of these seem like they need a lot of book-keeping and manual DOM traversal for something that sounds like the DOM already knows (since the document has its specific order).
You can use the Node.prototype.compareDocumentPosition method to find out if an element is prior to an other one:
const anchor = document.getElementById("anchor");
const markers = document.querySelectorAll(".marker"); // get all the markers in DOM order
const previous = [...markers].filter( // get only the markers before
(elem) => anchor.compareDocumentPosition(elem) === Node.DOCUMENT_POSITION_PRECEDING
).pop(); // get the last one
console.log( previous );
<div class="container">
<div>
<div>
<span>Some text<span class="marker">Marker 0</span></span>
<span>Some text<span class="marker">Marker 1</span></span>
</div>
<div>
<div>
<span>Foo</span>
<span id="anchor">THIS IS THE SELECTION ANCHOR NODE</span>
</div>
<span class="marker">Marker 2</span>
</div>
</div><!-- end of container -->
If I understand you correctly, this should get you there:
let xpath = '(//span[#class="marker"][not(.//preceding::*[contains(.,"SELECTION ANCHOR")])])[last()]',
result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
console.log(result.textContent);

Add classes within ngFor loop

How do I add different classes for the inner elements in an ngFor loop in Angular 4? Say, I have a snippet:
<div *ngFor="let article of articles">
<div>
<h3>{{article.name}}</h3>
<p>{{article.body}}</p>
</div>
</div>
So I have 2 questions: how do I add different classes to the h3 elements in every generated article based on their order (first, second, third) and how do I add classes to the h3 elements based on odd-even order?
You can get the index, odd, and even of the current iteration in the ngForOf, combine that with ngClass and you can set the class.
<div *ngFor="let article of articles; index as i; even as isEven; odd as isOdd">
<div id="article">
<h3 [ngClass]="{'odd': isOdd, 'even': isEven}">{{article.name}}</h3>
<p>{{article.body}}</p>
</div>
</div>
You do not mention how you want to use the index/position so there is no code for that. I am sure you can figure that part out though based on the sample code above and documentation.
As #Paco0 also pointed out maybe you meant id="article" to be id="{{article.id}}" or something similar?

Remove child objects from two parents in jQuery

I'm trying to remove parent tags from a list of links that are each inside a <p> and <span>
<p>
<span>
One
</span>
</p>
<p>
<span>
Two
</span>
</p>
↓
One
Two
jQuery:
$('p').each(function () {
$(this).html($(this).firstChild);
});
I've tried muliple ways of doing this but I just can't figure it out.
Assuming that the a tags will always be inside a single span and a single p tag you could call $("a").unwrap().unwrap(); You can learn more about .unwrap() here. I've included a working example below.
$("a").unwrap().unwrap();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
<span>
One
</span>
</p>
<p>
<span>
Two
</span>
</p>
If you don't know the exact HTML structure of the a elements in relation to their parent p, you can extract the a elements and then remove() the p completely:
$('p').each(function() {
$(this).find('a').insertBefore(this);
$(this).remove();
});
Example fiddle
This has the benefit of working for any level of nested a element.

Can't reach element by using a combination of .parent() and .next() methods

I'm binding the following function to a toggle button I have created to hide/unhide content that is located bellow the button, but on an other level in the DOM.
var togglelabel = packagehead.append("<div>").children().last().addClass("togglewrap").append("<label>")
.children().last().addClass("toggle android header-toggle")
.on('click', function(){
$(this).parent().parent().next('.hidable').toggle();
});
The html structure looks like this:
<div>
<div class="packageheader">
<span>Package #1501</span>
<div class="togglewrap">
<label class="toggle android header-toggle">
<input type="checkbox">
<p>
<span>More</span>
<span>Less</span>
</p>
<a class="slide-button">
</a>
</label>
</div>
</div>
<br>
<p class="hidable">
<pre>content here</pre>
</p>
</div>
This code doesn't work to hide the <p> with the class .hidable.
I've tried 'debugging' the code using console.log() to see what element 'this' represents and found that it does, as expected, represent the label element.
So I thought that using the following chain:
$(this).parent().parent().next('.hidable').toggle();
Would correctly go 2 levels up to the <div class="packageheader"> and then take the next sibling with the class hidable, which would be <p class="hidable">
Here is a screenshot of the structure, to be sure I didn't miss anything:
You can do this :
$(this).closest('.packageheader').nextAll('.hidable').first().toggle();
Note that it's slightly preferable to use closest instead of parent().parent() as it won't break as easily when the HTML changes and it's easier for the maintainer to decipher what the code does.
Note also that your HTML is invalid, you can't have a PRE inside a P.
Demonstration

CSS or jQuery Selector for span within span

I am trying to select a span within a span within a div using plain CSS or JQuery selectors. The html is as follows:
<div id="example2_paginate" class="dataTables_paginate paging_full_numbers">
<span id="example2_first" class="first paginate_button paginate_button_disabled">First</span>
<span id="example2_previous" class="previous paginate_button paginate_button_disabled">Previous</span>
<span>
<span class="paginate_active">1</span>
<span class="paginate_button">2</span>
<span class="paginate_button">3</span>
<span class="paginate_button">4</span>
<span class="paginate_button">5</span>
</span>
<span id="example2_next" class="next paginate_button">Next</span>
<span id="example2_last" class="last paginate_button">Last</span>
</div>
I want to select spans that contain 1 to 5 (paginate_active and the 5 paginate buttons), individually.
With my very limited knowledge of CSS and jQuery I've tried a couple of things but I'm sure my syntax is wrong, like $("paging_full_numbers span:eq(1)") .
Could you please give me a hint of how to go about it?
To select them individually, you can simply select them all and then use jQuerys .each(). For example
spanList = $('#example2_paginate').find('.paginate_active, .paginate_button');
will find all classes of 'paginate_active' or 'paginate_button' that, are inside your element of id=example2_paginate. Then you can write:
spanList.each(function(index){
<-- code here for occurence of index index-->
});
Alternatively to select the i^th button without looping through them all:
spanList.eq(i)
See jsFiddle: http://jsfiddle.net/t4KWr/
This CSS is what you want.
div.paging_full_numbers > span > span.paginate_active, div.paging_full_numbers > span > span.paginate_button
A quick way to get, say, the third of the 5 spans would be:
$(".paging_full_numbers > span > span:nth-child(3)")
its seem that there is a problem with
$("paging_full_numbers span:eq(1)")
You should write like
$("#paging_full_numbers span:eq(1)")
Or if you are using class
$(".paging_full_numbers span:eq(1)")
This select spans that contain 1 to 5 (paginate_active and the 5 paginate buttons), individually:
$("div.paging_full_numbers span:[class='paginate_active'],[class='paginate_button']").each(function(){
//do what you want here
});
That select the span's with only class 'paginate_active' or only class 'paginate_button'

Categories