Have been looking into the performance issues with the foreach and template binding. In our single page app, we have nested foreach/templates. Below is the jsperf url, which gives the information on a plain array rendered without a foreach and the one with foreach; where the test with title "Expanded loop markup" is better than the "Nested foreach" binding.
Also observed that the corrsponding "foreach via template" tests for nested and expanded are much more time consuming than the ones without foreach via template.
jsperf url:
http://jsperf.com/knockout-nested-foreach-vs-expanded-markup/2
Would appreciate your help on the performance with knockout 3.1.0
The performance issue is present with the knockout 3.2 version as well.
Want to know how to decrease the load time with nested foreach and/or template bindings.
In line with what Hans outlined, if you are really looking to squeeze the most performance out of the client-side. A custom binding working directly with the collection, building HTML as a string and injecting it using something like element.innerHTML.
A simple example below:
ko.bindingHandlers.innerHtml = {
init: function (element, valueAccessor) {
var lst = ko.unwrap(valueAccessor());
if (lst) {
var html = '';
for (var i = 0; i < lst.length; i++) {
html += '<li>' + lst[i] + '</li>';
}
if (html)
element.innerHTML = html;
}
}
};
var vm = function(){
var self = this;
self.lst = ko.observableArray();
for (var i = 0; i < 100; i++) {
var ary = [];
for (var j = 0; j < 1000; j++)
{
ary.push(j)
}
self.lst.push({ num: i, numAry: ary});
}
};
ko.applyBindings(new vm());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: $data.lst">
<li>
<span data-bind="text: num"></span>
<ul data-bind="innerHtml: numAry"></ul>
</li>
</ul>
Related
I want to convert the data of a Google Sheet into JSON format so that I can use it on my website. However, I get a 500 error whenever the website tries to fetch the JSON file.
I have already tried different methods to convert my sheet into JSON that are available on the internet
$url = 'https://spreadsheets.google.com/feeds/list/1dpmzzKNR8hRILX6qMD0KTruxxXYT3UAXR0EcX0zS0dE/1/public/full?alt=json';
$file= file_get_contents($url);
$json = json_decode($file);
$rows = $json->{'feed'}->{'entry'};
return $rows;
I had the same problem; I was able to work around the problem by parsing the html from the pubhtml page directly to output a similar JSON format:
Instead of using the Google Sheet ID, use the link for "Publish to Webpage".
There are some rows that I skip since some are for frozen rows, but you should be able to modify the code to your needs.
function importGoogleSheets(publishedUrl, sheetId, onSuccess, onError) {
var headers = [];
var rows;
$.ajax({
url: publishedUrl+'?gid='+sheetId+'&single=true',
success: function(data) {
data = $.parseHTML(data)[5];
htmldata = data;
rows = data.getElementsByTagName('tr');
for (var i = 0; i < rows[1].cells.length; i++) {
headers[i] = 'gsx$' + rows[1].cells[i].textContent.toLowerCase().replace(/[^0-9a-z]*/g, '');
}
for (var i = 3; i < rows.length; i++) {
temp = {};
for (var h = 1; h < headers.length; h++) {
temp[headers[h]] = {'$t': rows[i].cells[h].textContent};
}
all_data[i - 3] = temp;
}
onSuccess(all_data);
},
error: function(data) {
onError(data);
}
});
}
One note though is that it includes any empty rows unlike the feed, so you may want to filter the ouptut based on some column.
i am using javascript to add a series to a highchart. And i like to load the data to the series by an ajax call.
Here is my code:
function loadHighchartSeries(){
for (var i = 0; i < checkedGrpAdr3.length; i++) {
series_name = checkedGrpAdr3[i];
found = false;
for (var j = 0; j < chart.series.length; j++){
console.log(chart.series[j].name);
if (chart.series[j].name==series_name){
found = true;
}
}
if (!found){
datavar = ajax .... ????
chart.addSeries({
name: series_name,
data: datavar
});
}
}
}
The checkedGrpAdr3 is an array that contains the names of the series. First i check if the series name exists in the highchart graph. If it not exists it should load the data by using an ajax call and add a new series to the chart.
But how can i load the data by ajax and put it into the variable "datavar"?
Thanks
I am using the below code to loop through an XML document in order to get the "food" elements. I want to make sure that when an XML element is added it will be shown in the browser automaticaly as a list item.
var myNodeList = document.getElementsByTagName('food')
for (var i=0; i < myNodeList.length; i++) {
var output = '<ul>';
var food = request.responseXML.getElementsByTagName('food')[i];
I believe I was able to figure it out through the following approach:
var foodList = request.responseXML.getElementsByTagName('food')
for (var i=0; i < foodList.length; i++) {
var output = '<ul>';
var food = request.responseXML.getElementsByTagName('food')[i];
I have a problem, I like to show a select text values of a MultiSelect control on a tooltip.
I only can show the value(numeric) from MultiSelect, this is my code:
var multiselect = $("#combo_multi").data("kendoMultiSelect");
value2 = multiselect.value(); //show only numeric values ->14376, etc.
Show the numeric values together without spaces. ->14376
I like to show the text value, not the numeric value.
I think I have to use an array for show the text value, but I donĀ“t know how do it.
If somebody have the response of this problem, I appreciate the solution. Thanks.
Maybe this could help you a bit
var multiselect = $("#combo_multi").data("kendoMultiSelect");
var value2 = multiselect.value();
var selectedValues = value2.split(",");
var multiSelectData = multiselect.dataSource.data();
for (var i = 0; i < multiSelectData.length; i++) {
var numberValue = multiSelectData[i].number;
for (var j = 0; j < selectedValues.length; j++) {
if (selectedValues[j] == numberValue) {
// here we get description for value
var desc = multiSelectData[i].description;
break;
}
}
}
Example other
$("#multiselect").kendoMultiSelect();
var multiselect = $("#CityTo").data("kendoMultiSelect");
var dataItem = multiselect.dataItems();
//***Debug
var CityArray = new Array();
CityArray = dataItem;
alert(JSON.stringify(CityArray));
//***End Debug
//**************** Applied example
var newHtml = "";
var item = dataItem;
$.each(item, function (index, item) {
newHtml += '<div class="panel panel-default" ><div class="panel-heading">' + item.City_Name + '</div><div class="panel-body">Panel Content</div></div>';
});
$("#CityCount").html(newHtml);
You can see the details "dataItem" using "item."
item.City_Name
I'm on a newer version of Kendo UI so possibly things have changed since you asked this. I'll give you an updated answer..
var multiselect = $("#combo_multi").data("kendoMultiSelect");
var selectedValues = multiselect.value();
var multiSelectData = multiselect.dataSource.data();
var count = selectedValues.length;
for (var i = 0; i < multiSelectData.length; i++) {
if (selectedValues.indexOf(multiSelectData[i].Value) >= 0 ) {
//found, do something
var selectedText = multiSelectData[i].Text;
count--;
}
if (count == 0) {
break;
}
}
Using MVC3, C#, jQuery, Ajax ++
My html
<div>
Start Long Running Process
</div>
<br />
<div id="statusBorder">
<div id="statusFill">
</div>
</div>
The javascript part part of the html
var uniqueId = '<%= Guid.NewGuid().ToString() %>';
$(document).ready(function (event) {
$('#startProcess').click(function () {
$.post("SendToDB/StartLongRunningProcess", { id: uniqueId,
//other parameters to be inserted like textbox
}, function () {
$('#statusBorder').show();
getStatus();
});
event.preventDefault;
});
});
function getStatus() {
var url = 'SendToDB/GetCurrentProgress';
$.get(url, function (data) {
if (data != "100") {
$('#status').html(data);
$('#statusFill').width(data);
window.setTimeout("getStatus()", 100);
}
else {
$('#status').html("Done");
$('#statusBorder').hide();
alert("The Long process has finished");
};
});
}
This is the controller.
//Some global variables. I know it is not "good practice" but it works.
private static int _GlobalSentProgress = 0;
private static int _GlobalUsersSelected = 0;
public void StartLongRunningProcess(string id,
//other parameters
)
{
int percentDone = 0;
int sent = 0;
IEnumerable<BatchListModel> users;
users = new UserService(_userRepository.Session).GetUsers(
//several parameters)
foreach (var c in users)
{
var usr = _userRepository.LoadByID(c.ID);
var message = new DbLog
{
//insert parameters
};
_DbLogRepository.Save(message);
sent++;
double _GlobalSentProgress = (double)sent / (double)_GlobalUsersSelected * 100;
if (percentDone < 100)
{
percentDone = Convert.ToInt32(_GlobalSentProgress);
}
//this is supposed to give the current progress to the "GetStatus" in the javascript
public int GetCurrentProgress()
{
return _GlobalSentProgress;
}
Right now the div with the progress bar never shows up. It is honestly kind of broken. But I hope you understand my logic.
In the loop doing the insertions, I do have this calculation:
double _GlobalSentProgress = (double)sent / (double)_GlobalUsersSelected * 100;
Then I convert the _GlobalSentProgress to a normal int in the
percentDone = Convert.ToInt32(_GlobalSentProgress);
so it no longer has any decimals any longer.
If only I could send this "percentDone" or "_GlobalSentProgress" variable (wich is showing perfectly how many percent I have come in the insertion) asynchronous into the "data" variable in javascript every single time it loops, it would work. Then "data" would do it's "statusFill" all the time and show the bar correctly. This is the logic I use.
I believe the word thrown around in order to accomplish this is "asynchronous". I have looked at 2 very promising guides but I was not able to make it work with my loop.
Anyone have a suggestion on how I can do this?
Edit 2: Outer div is named statusBorder not status.