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
I have the following Google Chrome executeScript.
chrome.tabs.executeScript(
tabs[0].id,
{code: 'document.querySelectorAll(".col-9.col-md-10")[3].innerText'}, citationResult => {
console.log(citationResult);
});
This code gets the 4th element which has the classes col-9 AND `col-md-10' and then gets the inner text of that element. That is a string.
I would like a generalized query which instead returns every element which has col-9 AND `col-md-10'. However, when I try something like this:
chrome.tabs.executeScript(
tabs[0].id,
{code: 'document.querySelectorAll(".col-9.col-md-10")}, citationResult => {
console.log(citationResult);
});
I seem to get an empty array.
Is there a way to get those four elements returned rather than just getting the innerText of that single element?
As wOxxOm said, I needed to return an array of primitives. This is what solved my problem.
'var x = document.querySelectorAll(".col-9.col-md-10"); const finalArray = []; \n' +
'for (let i = 0; i < x.length; i++) {\n' +
' finalArray.push(x[i].innerText);\n' +
'} finalArray;'
I am developing an appointment booking system. It basically consists of a set of Polymer custom elements arranged as follows (indented elements are in the template of the element rather than actually organised as shown)
<my-appointments>
<person-appointment booking="{{booking}}>
<booking-type type="{{booking.type}}">
<div>[[booking.type]]</div>
</booking-type>
</person-appointment>
<appointment-day booking="{{booking}}>
<template is="dom-repeat" items="{{appointments}} as="{{appointment}}">
<div>[[appointment.type]]</div>
</template>
</appointment-day>
</appointment>
inside the <appointment-day> element booking is defined as an "Object" property and appointments as an "Array". As a booking is made, the booking object is spliced into the appointments array at the correct place.
At the same time I use the linkPaths function to join path 'booking' to path 'appointments.n' (where n is 0, 1, 2 etc for where in the appointments array booking is situated)
This is the code that does this
if (foundAppointment) {
//found where to insert appointment, so do so
this.splice(path, j, 0, this.booking);
this.linkPaths('booking', path + '.' + j);
this.linkedBooking = true;
break;
}
Not shown is a mechanism inside <booking-type> to update the type property. SO when I update the type property using this mechanism, the visual representation changes inside the <person-appointment> element but it does not change inside the dom-repeat. I can check that the object located at appointents[n] IS updated, but the display is not updated.
I presume I haven't properly linked booking to the appropriate appointment entry. BUT how should I achieve this
Polymer does not observe the change of sub-properties of appointments.
Try to Force data system to pick up array the mutations with the code below:
// Force data system to pick up the **array** mutations
var array = this.appointments;
this.appointments= [];
this.appointments= array;
Try to add this to your code.
if (foundAppointment) {
//found where to insert appointment, so do so
this.splice(path, j, 0, this.booking);
this.linkPaths('booking', path + '.' + j);
this.linkedBooking = true;
// Force data system to pick up array mutations
var array = this.appointments;
this.appointments= [];
this.appointments= array;
break;
}
Or to Force data system to pick up the Object mutations with the code below:
// Force data system to pick up array mutations
var object = this.appointment;
this.appointment= [];
this.appointment= object;
I'm only guessing that the problem is in binding to array items.
Polymer has special rules for that.
Here is one example of array binding: Plunk
<template is="dom-repeat" items="[[first4People(people, people.*)]]">
<div>
Index: <span>[[index]]</span>
<br>
First as this:[[arrayItem(people.*, index, 'first')]]
<br>
First not as this: <span>[[item.first]]</span>
</div>
<br><br>
</template>
Simplified online example of the problem would help to understand the issue better.
I am experimenting with a Firefox extension that will load an arbitrary URL (only via HTTP or HTTPS) when certain conditions are met.
With certain conditions, I just want to display a message instead of requesting a URL from the internet.
I was thinking about simply hosting a local webpage that would display the message. The catch is that the message needs to include a variable.
Is there a simple way to craft a local web page so that it can display a variable passed to it in the URL? I would prefer to just use HTML and CSS, but adding a little inline javascript would be okay if absolutely needed.
As a simple example, when the extension calls something like:
folder/messageoutput.html?t=Text%20to%20display
I would like to see:
Message: Text to display
shown in the browser's viewport.
You can use the "search" property of the Location object to extract the variables from the end of your URL:
var a = window.location.search;
In your example, a will equal "?t=Text%20to%20display".
Next, you will want to strip the leading question mark from the beginning of the string. The if statement is just in case the browser doesn't include it in the search property:
var s = a.substr(0, 1);
if(s == "?"){s = substr(1);}
Just in case you get a URL with more than one variable, you may want to split the query string at ampersands to produce an array of name-value pair strings:
var R = s.split("&");
Next, split the name-value pair strings at the equal sign to separate the name from the value. Store the name as the key to an array, and the value as the array value corresponding to the key:
var L = R.length;
var NVP = new Array();
var temp = new Array();
for(var i = 0; i < L; i++){
temp = R[i].split("=");
NVP[temp[0]] = temp[1];
}
Almost done. Get the value with the name "t":
var t = NVP['t'];
Last, insert the variable text into the document. A simple example (that will need to be tweaked to match your document structure) is:
var containingDiv = document.getElementById("divToShowMessage");
var tn = document.createTextNode(t);
containingDiv.appendChild(tn);
getArg('t');
function getArg(param) {
var vars = {};
window.location.href.replace( location.hash, '' ).replace(
/[?&]+([^=&]+)=?([^&]*)?/gi, // regexp
function( m, key, value ) { // callback
vars[key] = value !== undefined ? value : '';
}
);
if ( param ) {
return vars[param] ? vars[param] : null;
}
return vars;
}
http://localhost/catalog/{"request": "catalog","user_id": "test#gmail.com","purchased": "2"}
here goes my request URL. I need to test my service with a sample URL typed in browser. But it seems that many of the JSON items do not accepted by the server side. if i enter plane text string server works fine. I tried to encode the URL using http://www.albionresearch.com/misc/urlencode.php, but still the errors are there.
May be this is a problem which belongs to tapestry. Else i would like to get some help.
following request works.
http://localhost/catalog/helloworld
tapestry performs its own encoding of parameters within urls, which there is no replica for on the client side.
see org.apache.tapestry5.internal.services.URLEncoderImpl.encode(String)
the reason 'helloworld' works as expected is that there are no 'special characters' so the escaped value would equal 'helloworld' anyway.
So you will either need to encode your json via java using tapestry's URLEncoder or write a client side replica.
that is, if i understand your question properly.
EDIT i was bored so I wrote the client side replica:
/**
* see org.apache.tapestry5.internal.services.URLEncoderImpl.encode(String)
* correct as at tapestry 5.3.5
*/
function tapestryUrlEncodeParameter(input)
{
var safe = "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "01234567890-_.:";
if (input === null)
return "$N";
input = input.toString();
if (input === "")
return "$B";
var output = "";
for (var i = 0; i < input.length; i++)
{
var ch = input.charAt(i);
if (ch === '$')
{
output += "$$";
continue;
}
if (safe.indexOf(ch) != -1)
{
output += ch;
continue;
}
var chHex = ch.charCodeAt(0).toString(16);
while (chHex.length < 4)
chHex = "0" + chHex;
output += "$" + chHex;
}
return output;
}
What do you have server side? Either way you will have to decode your encoded json string on the server side if you want to do it this way.
A better solution might be to use a testing tool of some kind. This could be as simple as a jquery $.get request in a webpage or perhaps you might want to think about a more versatile HTTP client as suggested in this post
I am writing a jquery plugin that will do a browser-style find-on-page search. I need to improve the search, but don't want to get into parsing the html quite yet.
At the moment my approach is to take an entire DOM element and all nested elements and simply run a regex find/replace for a given term. In the replace I will simply wrap a span around the matched term and use that span as my anchor to do highlighting, scrolling, etc. It is vital that no characters inside any html tags are matched.
This is as close as I have gotten:
(?<=^|>)([^><].*?)(?=<|$)
It does a very good job of capturing all characters that are not in an html tag, but I'm having trouble figuring out how to insert my search term.
Input: Any html element (this could be quite large, eg <body>)
Search Term: 1 or more characters
Replace Txt: <span class='highlight'>$1</span>
UPDATE
The following regex does what I want when I'm testing with http://gskinner.com/RegExr/...
Regex: (?<=^|>)(.*?)(SEARCH_STRING)(?=.*?<|$)
Replacement: $1<span class='highlight'>$2</span>
However I am having some trouble using it in my javascript. With the following code chrome is giving me the error "Invalid regular expression: /(?<=^|>)(.?)(Mary)(?=.?<|$)/: Invalid group".
var origText = $('#'+opt.targetElements).data('origText');
var regx = new RegExp("(?<=^|>)(.*?)(" + $this.val() + ")(?=.*?<|$)", 'gi');
$('#'+opt.targetElements).each(function() {
var text = origText.replace(regx, '$1<span class="' + opt.resultClass + '">$2</span>');
$(this).html(text);
});
It's breaking on the group (?<=^|>) - is this something clumsy or a difference in the Regex engines?
UPDATE
The reason this regex is breaking on that group is because Javascript does not support regex lookbehinds. For reference & possible solutions: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript.
Just use jQuerys built-in text() method. It will return all the characters in a selected DOM element.
For the DOM approach (docs for the Node interface): Run over all child nodes of an element. If the child is an element node, run recursively. If it's a text node, search in the text (node.data) and if you want to highlight/change something, shorten the text of the node until the found position, and insert a highligth-span with the matched text and another text node for the rest of the text.
Example code (adjusted, origin is here):
(function iterate_node(node) {
if (node.nodeType === 3) { // Node.TEXT_NODE
var text = node.data,
pos = text.search(/any regular expression/g), //indexOf also applicable
length = 5; // or whatever you found
if (pos > -1) {
node.data = text.substr(0, pos); // split into a part before...
var rest = document.createTextNode(text.substr(pos+length)); // a part after
var highlight = document.createElement("span"); // and a part between
highlight.className = "highlight";
highlight.appendChild(document.createTextNode(text.substr(pos, length)));
node.parentNode.insertBefore(rest, node.nextSibling); // insert after
node.parentNode.insertBefore(highlight, node.nextSibling);
iterate_node(rest); // maybe there are more matches
}
} else if (node.nodeType === 1) { // Node.ELEMENT_NODE
for (var i = 0; i < node.childNodes.length; i++) {
iterate_node(node.childNodes[i]); // run recursive on DOM
}
}
})(content); // any dom node
There's also highlight.js, which might be exactly what you want.