I have a page that has an unordered list on it. I am populating the list via javascript like this:
var vidList = document.getElementById("vidList");
var li = document.createElement("li");
li.id = "videoPlayer" + count;
var runat = document.createAttribute("runat");
runat.value = "server";
li.setAttributeNode(runat);
// Here I insert a flash video stream into li
vidlist.appendChild(li);
This works as far as creating the elements and rendering them to the page. The issue is accessing them later. Since they are video streams I want to remove them when they are no longer valid streams. In my Visual Basic code behind I have the following code:
For videoNumber As Integer = 1 to numVideos
Dim li = vidList.FindControl("videoPlayer" & videoNumber.toString())
// Check if the stream is valid and delete it if it isn't
Next
When I debug the call to FindControl returns Nothing. So I looked through the local variables and found that my list had 5 elements all of which are Nothing. I looked at both this question and this one, but neither quite worked for my needs. Is there a reason that the list items are coming into the code behind as null values?
Request.Form['videoPlayer' + count]
More generally you can use Request.Form['clientID'] for dynamically created controls.
Related
Update: This is a better way of asking the following question.
Is there an Id like attribute for an Element in a Document which I can use to reach that element at a later time. Let's say I inserted a paragraph to a document as follows:
var myParagraph = 'This should be highlighted when user clicks a button';
body.insertParagraph(0, myParagraph);
Then the user inserts another one at the beginning manually (i.e. by typing or pasting). Now the childIndex of my paragraph changes to 1 from 0. I want to reach that paragraph at a later time and highlight it. But because of the insertion, the childIndex is not valid anymore. There is no Id like attribute for Element interface or any type implementing that. CahceService and PropertiesService only accepts String data, so I can't store myParagraphas an Object.
Do you guys have any idea to achieve what I want?
Thanks,
Old version of the same question (Optional Read):
Imagine that user selects a word and presses the highlight button of my add-on. Then she does the same thing for several more words. Then she edits the document in a way that the start end end indexes of those highlighted words change.
At this point she presses the remove highlighting button. My add-on should disable highlighting on all previously selected words. The problem is that I don't want to scan the entire document and find any highlighted text. I just want direct access to those that previously selected.
Is there a way to do that? I tried caching selected elements. But when I get them back from the cache, I get TypeError: Cannot find function insertText in object Text. error. It seems like the type of the object or something changes in between cache.put() and cache.get().
var elements = selection.getSelectedElements();
for (var i = 0; i < elements.length; ++i) {
if (elements[i].isPartial()) {
Logger.log('partial');
var element = elements[i].getElement().asText();
var cache = CacheService.getDocumentCache();
cache.put('element', element);
var startIndex = elements[i].getStartOffset();
var endIndex = elements[i].getEndOffsetInclusive();
}
// ...
}
When I get back the element I get TypeError: Cannot find function insertText in object Text. error.
var cache = CacheService.getDocumentCache();
cache.get('text').insertText(0, ':)');
I hope I can clearly explained what I want to achieve.
One direct way is to add a bookmark, which is not dependent on subsequent document changes. It has a disadvantage: a bookmark is visible for everyone...
More interesting way is to add a named range with a unique name. Sample code is below:
function setNamedParagraph() {
var doc = DocumentApp.getActiveDocument();
// Suppose you want to remember namely the third paragraph (currently)
var par = doc.getBody().getParagraphs()[2];
Logger.log(par.getText());
var rng = doc.newRange().addElement(par);
doc.addNamedRange("My Unique Paragraph", rng);
}
function getParagraphByName() {
var doc = DocumentApp.getActiveDocument();
var rng = doc.getNamedRanges("My Unique Paragraph")[0];
if (rng) {
var par = rng.getRange().getRangeElements()[0].getElement().asParagraph();
Logger.log(par.getText());
} else {
Logger.log("Deleted!");
}
}
The first function "marks" the third paragraph as named range. The second one takes this paragraph by the range name despite subsequent document changes. Really here we need to consider the exception, when our "unique paragraph" was deleted.
Not sure if cache is the best approach. Cache is volatile, so it might happen that the cached value doesn't exist anymore. Probably PropertiesService is a better choice.
I have a JSON response from a server, which returns me a array with 32 objects (in this case). Something like this:
[{object1},{ object2},{ object3}, etc].
Each object have some info that I use to populate an html template. For that, I just use a simple loop:
for(var i = 0; i < api_empresaListar.length; i++)
{
var item = api_empresaListar[i];
var htmls;
htmls = $('...lots of html code');
...
Then it’s just a simple matter of finding/changing the values, and append items on the DOM. Everything works fine. BUT, for some next parts of the code, I would like to access all the info from the object I used to build the html elements (I just show part of the info). So, after searching a lot, I tried to use data, like this:
var tp = htmls.find(".rl_grupo"); // the main div of each html element created in the loop
$(tp).data('key', api_empresaListar[i]); // here, I expected to just insert the object data in each created item.
But when I try it in the console, I got the object info as expected, but always from the last element in the array. Why is that happening? I believe it might be something stupid, but I can’t figure it out.
So, any ideas on how to solve this, or another method to make this work is appreciated. I made it work by setting some "display:none" placeholder html tags and populate those with the info I need later, but looks like a poor solution...
You should not set your htmls variable in the loop. I think that you crush its content every turn, that's why you only have the last item. You should do something like this:
var htmls = $('<div></div>');
for(var i = 0; i < api_empresaListar.length; i++) {
htmls.append($('...lots of html code'));
}
How about setting an index number on each element inside of your html creating code, then iterating over the $('.rl_grupo') elements, like this?
$('.rl_grupo').each(function(){
var index = $(this).data('index');
var currentData = api_empresaListar[index];
$(this).data('key', currentData);
})
I'm trying to create a Google sheets script which I hear is complete Javascript so I'm told. I'm just trying to create a list of quests relevant to an item in an online game by parsing the HTML in the spreadsheet.
Example: http://everquest.allakhazam.com/db/item.html?item=14295
Ideally in this case it should bring across the 4 quest names, their location and the quest ID (which can be found within the URL in the source code). But I'm just trying to pull the quest ID at the moment as can be found below.
function myFunction(itemid) {
var regexp = /quest.html\?quest\=(.*)"/;
var page = UrlFetchApp.fetch('http://everquest.allakhazam.com/db/item.html?item=' + itemid).getContentText();
var matches = [];
var number = page.match(/<li><a href="\/db\/quest.html\?quest\=(.*)"/);
for (var i in number) {
matches.push(number[i]);
}
return matches;
}
But the script just seems to hang on 'Loading..' and doesn't do anything. If I add 'return number just after the page.match it returns the first quest ID fine.. so it seems it may be related with pushing to the array which is causing the issues.
It is better not to parse HTML as text. You can use a formula with importxml function to get your data using XPath:
=importxml("http://everquest.allakhazam.com/db/item.html?item=14295";"//div[#id='quest']//b|//div[#id='quest']/ul/li/a|//div[#id='quest']/ul/li/a/#href")
I am trying to obtain the <RowDefinitions> element from my Xaml, through Javascript, so I can add new <RowDefinition> elements to it at runtime.
This way, if a user inputs the number '20', then 20 <RowDefinition> elements will be added to <RowDefinitions>.
The problem is that <RowDefinitions> does not have a possibility for x:Name. It only has x:uid. So would it be possible to fetch the uid from within Javascript? I need the <RowDefinitions> Element one way or another (but only through JS). I need to add <RowDefinition> elements to it.
Any ideas?
Thanks
Assuming Javascript API
There is no such element as <RowDefinitions> you will be refering to the RowDefinitions property of a Grid element which is represented as <Grid.RowDefinitions> in Xaml. Hence you use FindName to aquire the Grid then use GetValue to get the collection of row definitions. Lets assume you have this simple Xaml to start with:-
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="rootGridLoaded" />
So in your Javascript you have can have this code:-
function rootGridLoaded(sender)
{
var plugin = sender.getHost();
var rowDefs = sender.GetValue("RowDefinitions");
for (var i=0; i < 20; i++)
{
var rowDef = plugin.content.createFromXaml("<RowDefinition />");
rowDefs.add(rowDef);
}
}
This will get the RowDefinitions collection from the Grid (which in this case is the sender but you just as easily have used FindName to get a named grid. Then it loops adding 20 RowDefintion instances ot the collection.
I have a database webmethod that I call via Jquery ajax. This returns an array of data objects from the server. For each data object I want to populate a form with maybe a couple dozen fields.
What is the most efficient way to generate and populate these forms.
Right now, I create a string of the html in my javascript code for each record and then add it to the page. Then I add some events to the new elements.
This works OK in firefox, about 700 ms total for an array of 6 elements, and 4500 ms for an array of 30 elements. However, this is an internal app for my company, and the clients can only use IE8 on their machines. In IE8, this takes 2-10 SECONDS! for and array of length 6 and 47 seconds the one time it was actually able to complete for an array of length 30. Not sure what the ##$% IE8 is doing, but anyways... I need something more efficient it seems...
Thanks!
MORE INFO:
Edit: first thing I do is:
$("#approvalContainer").empty();
Web method signature:
[WebMethod]
public List<User> ContractorApprovals()
So I call the method and then do this with the data:
for (var i = 0; i < data.length; i++) {
displayUserResult("#approvalContainer", data[i], false);
}
formEvents("#approvalContainer");
$("#approvalContainer").show("slow");
displayUserResult looks like this:
var div = "<div style=\"width:695px\" class=..........."
fillForm(div,data)
$("#approvalContainer").append(div)
formEvents does things like add click events, create styles buttons and add watermarks.
fillForm does stuff like this:
$(userForm).find(".form-web-userName").text(userObject._web._userName);
where userForm is the div created in the displayUserResult function, and userObject is one of the objects in the array returned by the ajax call.
Please let me know if you need more information.
You are doing too much DOM manipulation. Every .append and .find and .text inside your loop makes it slower.
The most efficient way is to build an entire HTML string and append that once. I'm not going to bother with the displayUserResult function, and just modify your function that handles the data:
var div = "<div style=\"width:695px\" class=...........",
html = "";
for (var i = 0; i < data.length; i++) {
// Keep adding on to the same html string
html += div + data[i]._web._userName + "</div>";
}
// After the loop, replace the entire HTML contents of the container in one go:
$("#approvalContainer").html(html);
However, while this is fast, note that this is only appropriate if _userName doesn't contain special characters, or is already HTML escaped.