Dynamically assign variable in Go template [duplicate] - go

I have a Golang array I'm passing to my html file on the front end.
I know that
'{{ index .Array 0}}'
works and pulls the first element from the array. But I want to do a Javascript for-loop and print every element in the array like so
<script type="text/javascript">
function loop() {
html = ""
for(var i = 0; i<5; i++) {
html += "{{ index .Array " + i + "}}";
}
}
But this doesn't work. Something about separating the go array index string, HTML/Javascript doesn't like it and it won't load.
It's a syntactical error that I just can't pin down.
Any ideas?

You need to understand something:
Template actions such as {{index .Array 0}} are executed at server side in your Go application.
Javascript code is interpreted and run at client side in the browser.
The template parameter value used in template actions (Array in your example) does not exist at client side (e.g. as a Javascript object). And Javascript code is not run by the template engine. So the template parameter (value) and Javascript (execution) live in 2 different "spaces".
Having said that, it is not possible to mix template actions/variables and Javascript execution.
You have 2 options:
1) Do what you want to do with template actions.
2) Use the template to create Javascript code which when executed at the client side will construct/recreate the array as a Javascript object so it will be available for further Javascript processing.
Note that if you just want to loop over the array once, creating a Javascript array is not neccessary, you can simply render the JavaScript code that would be the loop body inside a {{range}} template action. See Simon's answer as an example to this.
Elaborating #1
You can use the {{range .Array}} action to loop over Array, and the block is executed for each element, pipeline set to the array element so you can output the array elements like this:
{{range .Array}}
{{.}}
{{end}}
Of course you can put anything else inside the block, not just the array elements. You can even access the current index like this:
{{range $idx, $value := .Array}}
Index = {{$idx}}; Element = {{$value}}<br>
{{end}}
Elaborating #2
Let's say your Array contains int numbers, you can recreate it in Javascript and loop over it in Javascript with a template like this:
<script>
var arr = [
{{range .Array}}
{{.}},
{{end}}
];
// Now you have a javascript array: arr, loop over it to do something:
html = "";
for(var i = 0; i < arr.length; i++) {
html += " " + arr[i];
}
</script>
Or since the template engine supports "rendering" arrays and slices as JavaScript arrays, you can simply write:
<script>
var arr = {{.Array}};
// Now you have a javascript array: arr, loop over it to do something:
html = "";
for(var i = 0; i < arr.length; i++) {
html += " " + arr[i];
}
</script>

You're not "passing a Golang array to the front end" .. your template is being rendered server side. That is an important distinction.
When you think about it like that .. the syntactic issue becomes clear. You are attempting to intermix Go's template syntax with Javascript right in the middle of expressions. That simply isn't correct. You should use a Go loop that, when rendered, produces valid Javascript for the client to consume:
var javaScriptHtmlVariable = "";
{{ range .Array }}
javaScriptHtmlVariable += '{{.}}';
{{ end }}
Which would render:
javaScriptHtmlVariable += 'One';
javaScriptHtmlVariable += 'Two';
javaScriptHtmlVariable += 'Three';
javaScriptHtmlVariable += 'Four';
// etc..

Related

Use Cypress functions on variables

I'm looping throw all of the .row and need to grab the inner elements within .row. Is there a way to do this? I wasn't able to find any documentation on this on Cypress' website.
let num = 0
cy.get('.row').each(row => {
let rowDiv = cy.get(row).get('div') // not correct
let rowBtn = cy.get(row).get('button') // not correct
cy.get(rowDiv).should('have.text', 'Task ' + num)
cy.get(rowBtn).should('have.text', "Btn ' + num)
num++
})
You can use cy.wrap() to turn the yielded JQuery elements back into Cypress Chainables. Additionally, cy.each() can yield you the index of the current iteration, so instead of having to use num, you could just use that index variable.
cy.get('.row')
.each((row, rowIndex) => { // yields JQuery element and current iteration
cy.wrap(row).find('div').should('have.text', `Task ${rowIndex}`);
cy.wrap(row).find('button').should('have.text', `Btn ${rowIndex}`);
});

How to use ForEach controller on an array?

jmeter ForEach controller can be used to iterate over variables with same prefix like,
myVar_1
myVar_2
myVar_3
But in my case input variable is array of strings, [ "val1", "val2", "val3" ] How to iterate over an array and send separate request for each value?
You won't be able to feed this JSON Array to the ForEach Controller, but you can convert it into a form which can be understood by the ForEach Controller
Add a JSR223 Sampler after the variable holding this JSON Array is defined
Put the following code into the "Script" area:
def json = new groovy.json.JsonSlurper().parseText(vars.get("yourInputVariable"))
def counter = 1
json.each {
vars.put("myVar_" + counter, it)
counter++
}
Replace yourInputVariable with the actual name of the variable holding the JSON Array
Add ForEach Controller under the JSR223 Sampler and perform "normal" configuration as you would do it for myVar_1, myVar_2,... - it will work fine as JSR223 Sampler creates the relevant variables basing on the data from the JSON Array.
See Parsing and producing JSON - Groovy and Groovy Is the New Black articles for more information.
Same way as you use for same prefixed variables.
For variable myVar
myVar = ["val1", "val2", "val3"];
//Following variables are automatically created
myVar_1 = "val1";
myVar_2 = "val2";
myVar_3 = "val3";
ForEach controller will be used on myVar_1, myVar_2, myVar_3
Use Debug Sampler to ensure.
jmeter version : 3.1 r1770033
I tried Dmitri's answer, but basically got stuck with the groovy script as it works only for a simple array of strings. I, however, needed a more complex array of JSON objects.
Then I switched the scripting language to ecmascript and based on the original script wrote a good old JS like this:
var jsonObject = JSON.parse(vars.get("ReportSources"));
for(var index = 0; index < jsonObject.length; index++) {
vars.put("rs_" + (index + 1), JSON.stringify(jsonObject[index]));
}
It worked for me.

Remove HTML formatting in Razor MVC 3

I am using MVC 3 and Razor View engine.
What I am trying to do
I am making a blog using MVC 3, I want to remove all HTML formatting tags like <p> <b> <i> etc..
For which I am using the following code. (it does work)
#{
post.PostContent = post.PostContent.Replace("<p>", " ");
post.PostContent = post.PostContent.Replace("</p>", " ");
post.PostContent = post.PostContent.Replace("<b>", " ");
post.PostContent = post.PostContent.Replace("</b>", " ");
post.PostContent = post.PostContent.Replace("<i>", " ");
post.PostContent = post.PostContent.Replace("</i>", " ");
}
I feel that there definitely has to be a better way to do this. Can anyone please guide me on this.
Thanks Alex Yaroshevich,
Here is what I use now..
post.PostContent = Regex.Replace(post.PostContent, #"<[^>]*>", String.Empty);
The regular expression is slow. use this, it's faster:
public static string StripHtmlTagByCharArray(string htmlString)
{
char[] array = new char[htmlString.Length];
int arrayIndex = 0;
bool inside = false;
for (int i = 0; i < htmlString.Length; i++)
{
char let = htmlString[i];
if (let == '<')
{
inside = true;
continue;
}
if (let == '>')
{
inside = false;
continue;
}
if (!inside)
{
array[arrayIndex] = let;
arrayIndex++;
}
}
return new string(array, 0, arrayIndex);
}
You can take a look at http://www.dotnetperls.com/remove-html-tags
Just in case you want to use regex in .NET to strip the HTML tags, the following seems to work pretty well on the source code for this very page. It's better than some of the other answers on this page because it looks for actual HTML tags instead of blindly removing everything between < and >. Back in the BBS days, we typed <grin> a lot instead of :), so removing <grin> is not an option. :)
This solution only removes the tags. It does not remove the contents of those tags in situations where that might be important -- a script tag, for example. You'd see the script, but the script wouldn't execute because the script tag itself gets removed. Removing the contents of an HTML tag is VERY tricky, and practically requires that the HTML fragment be well formed...
Also note the RegexOption.Singleline option. That's very important for any block of HTML. as there's nothing wrong with opening an HTML tag on one line and closing it in another.
string strRegex = #"</{0,1}(!DOCTYPE|a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdi|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|datalist|dd|del|details|dfn|dialog|dir|div|dl|dt|em|embed|fieldset|figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|main|map|mark|menu|menuitem|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|tt|u|ul|var|video|wbr){1}(\s*/{0,1}>|\s+.*?/{0,1}>)";
Regex myRegex = new Regex(strRegex, RegexOptions.Singleline);
string strTargetString = #"<p>Hello, World</p>";
string strReplace = #"";
return myRegex.Replace(strTargetString, strReplace);
I'm not saying this is the best answer. It's just an option and it worked great for me.

How To Elegantly Handle JSON Objects in Responses From Ajax Requests?

I'm really new to using JSON to handle my Ajax Request and Response cycle. I've previously used just plain old parameters passed as POST data and I've rendered straight HTML in the response which was then placed into the DOM. As I've looked at various examples and read through various tutorials, it seems like a fairly common practice to simply build a string from the JSON object mixed with HTML that's been hard coded into the string and then assign the string as innerHTML to some element.
A common example looks something like this:
var jo = eval(req.responseText);
var strTxt = '<span>' + jo.f_name + ' ' + jo.l_name + '</span><br/>' + 'Your Age Is: ' + jo.age + '<br/>';
$('myDiv').innerHTML = strTxt;
Is there a more elegant (or correct) way of handling the JSON response so that I'm not hard coding HTML in the javascript? Or is this pretty much how people do it?
P.S. Links to tutorials or other sources are appreciated.
I steer away from writing a lot of HTML within JavaScript strings. I prefer separation of structure from data manipulation. The better alternative is to place that code in the page, load the values based off the ID's, and show/hide it if necessary:
<div id="codeBlock" style="visible=false;">
<span id="val1"></span>
<br/>
<span id="val2"></span>
<br/>
</div>
............
<script>
var jo = eval(req.responseText);
$('val1').innerHTML = jo.f_name + ' ' + jo.l_name;
$('val2').innerHTML = 'Your Age Is: ' + jo.age;
$('codeBlock').show();
</script>
That might not be exactly what you want to do but you get the idea.
You could create the elements in the DOM using javascript instead of just dropping them into the innerHtml of the DIV, something like the following (untested):
var mySpan = document.createElement("span");
var spanContent = document.createTextNode(jo.f_name + ' ' + jo.l_name);
mySpan.appendChild(spanContent);
var myBr = document.createElement("br");
mySpan.appendChild(myBr);
var otherSpanContent = document.createTextNode('Your Age Is: ' + jo.age);
mySpan.appendChild(otherSpanContent);
mySpan.appendChild(myBr);
$('myDiv').appendChild(mySpan);
You could check out a templating engine such as PURE - may be a bit hard to get into at first but it supports many major javascript frameworks (and DOMAssistant which is nice) and separates html from the data.
The objects created from JSON are standard Javascript objects, therefore you can easily use jQuery selectors to create or access DOM elements and insert content from your JSON objects.
eg.
// Create a new span element and set its text
var personSpan=$("<span>").text(jo.f_name + ' ' + jo.l_name);
// Append the span to the existing myDiv element
$("myDiv").append(personSpan);
// Create a new div element (better then br) and set its text
var personDiv=$("<div>").text("Your Age Is: " + jo.age);
// Append the new div to the existing myDiv element
$("myDiv").append(personDiv);

How to apply successively two xpath expressions with libxml?

To sum up, i'm a totally beginner in libxml and I have to use an existing source code. The main idea is to apply a first xpath expression to extract a set of nodes from an xml file. Then, for each node, the second xpath expression shall be applied to extract some values.
Existing source code is:
int xt_parseXmlResult(xmlDocPtr doc, const char *xpath, assoc_arrayc_t expr, arrayc_t *result)
{
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
// Register namespaces ...
/*
* Evaluate main xpath expression
*/
xmlXPathObjectPtr xpathNodes = xmlXPathEvalExpression((xmlChar *)xpath, xpathCtx);
/*
* Now we apply the xpath expressions on each node returned by the first xpath request
*/
// First loop is on the XML document as we have to create a new context each
// time we change the document
int nbDocs = xpathNodes->nodesetval->nodeNr;
for (row = 0; row < nbDocs; row++)
{
xmlXPathContextPtr subCtx = xmlXPathNewContext(doc);
// Register namespaces ...
// Update context to use the nodeset related to this row
subCtx->node = xpathNodes->nodesetval->nodeTab[row];
for (col = 0; col < expr.nbItems; col++)
{
// Evaluate expression
xpathRows = xmlXPathEvalExpression((xmlChar *)expr.itemList[col].val, subCtx);
result->data[(row + 1) * result->nbCols + col] = strdup((char *)xmlXPathCastToString(xpathRows));
xmlXPathFreeObject(xpathRows);
}
xmlXPathFreeContext(subCtx);
subCtx = NULL;
}
xmlFreeDoc(doc);
xmlXPathFreeContext(xpathCtx);
xmlXPathFreeObject(xpathNodes);
return 0;
}
I think that the problem comes from this line
// Update context to use the nodeset related to this row
subCtx->node = xpathNodes->nodesetval->nodeTab[row];
Because the second xpath expression is applied from the root of the xml file, not the root of each node.
Any idea on how to do such thing?
you could concatinate your xpath expressions.
edit
//FORECAST/DAY/descendant::content/meteo/desc should work
as i see in the xmlXPathContext::node is for internal library use, so we can not use it
Probably xmlXPtrNewContext should help, but i am not able to use it.
I currently do the trick with concatenating both xpaths and quering the whole.
The new xpath is: "(" + xpath1 + ")" + "[num]" + xpath2.
Where num can be replaced with any number betwen 1 and the size of xpath1 result set.
And it seem to work.
Some sample code. Modify to suit your needs and language. This is C#, but it should be largely the same. Notice the second xpath is not starting with a "/" and is using an instance of the node returned from the first one. Neither of the xpaths end in a "/".
XmlDocument doc = new XmlDocument();
doc.Load(docfile);
XmlNodeList items = doc.SelectNodes("/part1/part2");
foreach (item in items)
{
XMLNode x = item.SelectNodes("part3");
//Dostuff
}

Resources