I'm learning D3. In this example, I'm adding paragraphs, using a simple list of numbers as data. I try to do the following things:
Start with a list of 5 elements. When I call update(), I think the enter selection should contain 5 paragraphs and the exit() selection should be empty.
Add one number to the data. The enter selection should contain this single paragraph and the exit selection should be empty.
Remove all the numbers except for two. Here the exit selection should contain 4 paragraphs and the enter selection should be empty.
However, this is not what I see! I make the update function print the amount of elements, like this:
console.log('paras: '+paras[0].length+ ' enter: '+parasE[0].length + ' exit: '+paras.exit()[0].length);
And, for the three times it is called, I get this output:
"paras: 5 enter: 5 exit: 5"
"paras: 6 enter: 6 exit: 6"
"paras: 6 enter: 6 exit: 6"
As I understand it, as I'm using indexing to do the data join (and not a key), either the exit selection or the enter selection are always empty. Am I misunderstanding this, or am I using the wrong method to check how many elements are in the selections?
It seems that all elements are being removed and re-added each time (which is why the enter and exit selections are both full). What am I misunderstanding?
Thanks,
Louise
Full example code (will run from a local HTML file):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>D3 Hello World</title>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.4.5"></script>
</head>
<body>
<script type="text/javascript">
d3.select("body").append("span")
.text("Hello, world!");
data1=[1,2,3,4,5];
function update(){
paras=d3.select('body').selectAll('p').data(data1);
parasE=paras.enter();
console.log('paras: '+paras[0].length+ ' enter: '+parasE[0].length + ' exit: '+paras.exit()[0].length);
paras.enter().append('p').html(function(d){return d});
paras.exit().remove();
}
update();
data1.push(10);
update();
data1=[1,2];
update();
</script>
</body>
</html>
The reason is that D3 selections aren't quite arrays and shouldn't be treated as such. In particular (from the documentation):
One nuance is that selections are grouped: rather than a one-dimensional array, each selection is an array of arrays of elements.
You're simply getting the size of the wrong selection arrays. Use .size() to get the size of a selection:
console.log('paras: '+paras.size()+ ' enter: '+parasE.size() + ' exit: '+paras.exit().size());
Complete example here.
Related
I have this html sample
<html>
<body>
....
<p id="book-1" class="abc">
<b>
book-1
section
</b>
"I have a lot of "
<i>different</i>
"text, and I want "
<i>all</i>
" text and we may or may not have italic surrounded text."
</p>
....
the xpath I currently have is this:
#"/html[1]/body[1]/p[1]/text()"
this gives this result:
I have a lot of
but I want this result:
I have a lot of different text, and I want all text and we may or may not have italic surrounded text.
Thanks for your help.
In XPath 2 and higher you could use string-join(/html[1]/body[1]/p[1]/b/following-sibling::node(), '') I think. It is not quite clear which nodes you want but that would select all sibling nodes following the b child of the p and then concatenate their string values into one.
I'm using kendo ui and I tried setting a tooltip template like this:
tooltip.template = "#= series.name #: #= kendo.toString(value, 'n') # "
But the numbers like 527266 are showing like this : 527.266,00
How can I make it 527.266 ?
I tried as test:
tooltip.template = "#= series.name #: #= kendo.toString(value, '##,#') # "
which is an example in the documentation, and should give 527,266 according to the example but it's caughting an error of Invalid Template.
How can I make numbers 527266 look 527.266
You can use (kendo.toString(527266 , 'n0') to hide decimal numbers. Since it is culture specific, you will need to include culture specific JavaScript file.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="http://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.3.1028/js/kendo.all.min.js"></script>
</head>
<body>
<p>Input: 527266</p>
<p>Output: <span id="result"></span></p>
<script src="http://kendo.cdn.telerik.com/2013.2.716/js/cultures/kendo.culture.de-DE.min.js"></script>
<script>
kendo.culture("de-DE");
$("#result").text(kendo.toString(527266 , 'n0')); // outputs "527.266"
</script>
</body>
</html>
I'm not able to find another way to kendo format as I'm pleased. the only workaround I'm using till now is:
template: "#= formatAmount(FundCurrency ,FundValue) #"
and in your Js create a function.
function formatAmount(currency, amount) {
if (amount) return currency + " " + kendo.toString(amount, "#,##0.00");
return "";
}
All this trouble just because # inside the format is conflicting with the special tags #= ... #, and unless you start to format the string using "\#,\#\#0.00" it won't work, I guess.
I was having the same problem as you, although I wanted to show up to 6 decimals but not complete with 0, aka: "123,123456" should look like "123,123456" but "123,12" like "123,12", with no trailing 0s.
If you want no decimal places, then you could use:
template: "#= kendo.format("{0:n0}", value) #
Or change the 0 part of n0 to add fixed decimal places. For example for 3 decimal places it will look like this:
template: "#= kendo.format("{0:n3}", value) #
Now, if you want what I needed, which was a dynamic amount of decimal places, then th only way of doing it is with a js function:
template: "#= formatAmount(value) #
function formatAmount(amount) {
return kendo.toString(amount, "#,###.######");
}
Not 100% sure if this is possible, but hoping there is a workaround. Several hours of searching bring nothing up. I have a text string written to the page from a Db table. If it contains a specific string, I would like to add a page include - example below does write:
<!--#include file="members.asp"-->
into the text, but does not pull the included file content in.
<%=Replace(myQuery("Text"), "123456", "%><!--#include file="mypage.asp"--><% ")%>
Client wants it in the page rather than at the top or bottom of the output which would be so easy (and we already do that) The include has to go in at a specific point in the text.
I would appreciate any help, even if it is to confirm that it is not possible to do this.
Here is the main page:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body onload="document.getElementById('placeholder').innerText = document.getElementById('alwaysfillme').innerText">
<p><%=Replace("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "J", "<span id=""placeholder""></span>")%></p>
<span id="alwaysfillme" style="display:none;"><!--#include file="mypage.asp"--></span>
</body>
</html>
And here is what I stuck in "mypage.asp":
<% response.Write("--123--") %>
When a J is in the text, it displays:
ABCDEFGHI--123--KLMNOPQRSTUVWXYZ
When no J is in the text, it displays:
ABCDEFGHIKLMNOPQRSTUVWXYZ
<%=Replace(myQuery("Text"), "123456", ""&Server.Execute("mypage.asp")&"")%>
I am trying to build a simple search-engine using HtmlAgilityPack and Xpath with C# (.NET 4).
I want to find every node containing a userdefined searchword, but I can't seem to get the XPath right.
For Example:
<HTML>
<BODY>
<H1>Mr T for president</H1>
<div>We believe the new president should be</div>
<div>the awsome Mr T</div>
<div>
<H2>Mr T replies:</H2>
<p>I pity the fool who doesn't vote</p>
<p>for Mr T</p>
</div>
</BODY>
</HTML>
If the specified searchword is "Mr T" I'd want the following nodes: <H1>, The second <div>, <H2> and the second <p>.
I have tried numerous variants of doc.DocumentNode.SelectNodes("//text()[contains(., "+ searchword +")]"); but I always seem to wind up with every single node in the entire DOM.
Any hints to get me in the right direction would be very appreciated.
Use:
//*[text()[contains(., 'Mr T')]]
This selects all elements in the XML document that have a text-node child which contains the string 'Mr T'.
This can also be written shorter as:
//text()[contains(., 'Mr T')]/..
This selects the parent(s) of any text node that contains the string 'Mr T'.
According to Xpath, if you want to find a specific keyword you need to follow the format ("keyword" is the word you like to search) :
//*[text()[contains(., 'keyword')]]
You have to follow the same format as above in C#, keyword is the string variable you call:
doc.DocumentNode.SelectNodes("//*[text()[contains(., '" + keyword + "')]]");
Use the following:
doc.DocumentNode.SelectNodes("//*[contains(text()[1], " + searchword + ")]")
This selects all elements (*) whose first text child (text()[1]) contains the searchword.
Case-insensitive solution:
var xpathForFindText =
"//*[text()[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '" + lowerFocusKwd + "')]]";
var result=doc.DocumentNode.SelectNodes(xpathForFindText);
Note:
Be careful, because the lowerFocusKwd must not contain the following character, because the xpath will be in bad format:
'
I'm trying to build a list of checkboxes by using jQuery.tmpl
It'll list an array of items with a checkbox near them, and I want to check some of these checkboxes parametrically...
The template code is:
<ul>
{{each(i,val) Values}}
<li>
<input type="checkbox" {{if $.inArray(i, Default) != -1}} checked="checked"{{/if}}>
<em>${val}</em>
</li>
{{/each}}
</ul>
and the template definition:
<script type="text/javascript">
$(document).ready(function() {
$('#tpl_selector').tmpl({
Default: [1,2],
Values: {
1: 'Item 1',
2: 'Item 2',
3: 'Item 3'
}
}).appendTo('#area');
});
</script>
So the Item 1 and Item 2 should be checked in this case. The list is created with no problem, but {{if $.inArray(i, Default) != -1}} checked="checked"{{/if}} part is not working.
However, when I replace 'i' with a number, it works:
{{if $.inArray(1, Default) != -1}} checked="checked"{{/if}}
I doesn't make any sense at all... Do you have any suggestions?
Another logic to fill the checkboxes is ok too, like I don't know smt. like a callback function after the rendering completes or else...
The problem
In JavaScript objects, the key is always a string. Your Default array contains numbers, but the "needle" you're passing in (i) is a string, so $.inArray will always return false,.
jsfiddle 0
The solutions
Any one of these will work:
Make Values a proper array, rather than an object "indexed" by strings containing numbers.
jsfiddle 1 (Note the zero-based indexing!)
Make Defaults an array of strings.
jsfiddle 2
parseInt() the Values key (i) when you pass it to $.inArray(). I think this is an ugly fix.
jsfiddle 3
Oh, and welcome to Stack Overflow!