Slickgrid basic example - In node/express, only first row of data loads but is not visible - node.js

I'm trying to run a barely modified version of SlickGrid's example1-simple.html. I'm on Mac OS X Lion, seeing the same behavior with Chrome/Safari/Firefox. Once I have all of the CSS/JS dependencies in place I can directly load the example HTML page (and my slightly modified version) without any trouble. However when I try to serve basically the same page with node/express/jade (using res.render()), the header (column names) row loads, and looking through the rendered HTML I can see that the first row of my data loads but I don't see it in the browser (I'm trying to load 10 rows of data). All of the relevant CSS/JS files seem to be loading properly and I don't see any errors either in the browser console or my node console. I've copied the entirety of the grid-canvas div below.
<div class="grid-canvas" style="height: 250px; width: 240px; ">
<div class="ui-widget-content slick-row even" row="0" style="top:0px">
<div class="slick-cell l0 r0">Battery test #1.csv</div>
<div class="slick-cell l1 r1">1024</div>
<div class="slick-cell l2 r2">1335237255112</div>
</div>
</div>
I'm pretty sure the JavaScript is all right, as it pretty much exactly matches the example HTML page and runs fine when I substitute it in the example1-simple.html document and access it directly. Also when rendering the page with express I can set a breakpoint in my browser at the new Slick.Grid() call and see that the 10-item array of row data is being sent, just not ultimately rendered.
I have basic old-school debug skills (once upon a time I did a lot of Windows programming in VB) but I'm very open to suggestions as to relevant debug tools and techniques I could bring to bear on this type of problem.
Here is my layout.jade:
!!!
html
head
title= title
link(rel="stylesheet", href="/stylesheets/slick.grid.css", type="text/css")
link(rel="stylesheet", href="/stylesheets/css/smoothness/jquery-ui-1.8.19.custom.css", type="text/css")
body!= body
And the jade page with my test code:
#content
#fileGrid
script(src="/javascripts/lib/jquery-1.7.2.js")
script(src="/javascripts/lib/jquery.event.drag-2.0.min.js")
script(src="/javascripts/lib/slick.core.js")
script(src="/javascripts/lib/slick.grid.js")
script
var grid;
var columns = [
{id: "fileName", name: "File Name", field: "fileName"},
{id: "fileSize", name: "File Size", field: "fileSize"},
{id: "lastUpdate", name: "Last Updated", field: "lastUpdate"} // use mtime
];
var options = {
enableCellNavigation: true,
enableColumnReorder: false
};
$(function() {
var timeStamp = new Date();
var numRows = 10;
var data = [];
for (var i = 1 ; i <= numRows ; i++) {
data[i-1] = {
fileName: "Battery test #" + i + ".csv",
fileSize: i * 1024,
lastUpdate: Date.now().toString()
}
};
grid = new Slick.Grid("#fileGrid", data, columns, options);
});

I figured it out. The problem was that I didn't specify a size for my #fileGrid div either in my jade/html or anywhere else in the css, and SlickGrids seemed to assume that the size was zero, and thus didn't render any rows. I changed the jade declaration to #fileGrid(style="width:500px; height:600px) and that fixed it. In retrospect that was really the only thing different between my jade page and the html example.

This looks fishy:
for (var i = 0 ; i <= numRows ; i++)
data[i-1] = {
fileName: "Battery test #" + i + ".csv",
fileSize: i * 1024,
lastUpdate: Date.now().toString(),
};
Why data[i-1] and i <= numRows? You're trying to assign to data[-1] up until data[numRows], where you should assign to data[0] until data[numRows - 1].
On a side note, I would wrap that for loop in braces, even though it's not strictly necessary. Also, the trailing comma (on the last row) will break in Internet Explorer:
for (var i = 0 ; i < numRows ; i++) {
data[i] = {
fileName: "Battery test #" + i + ".csv",
fileSize: i * 1024,
lastUpdate: Date.now().toString()
};
}
You also have a trailing comma in your columns assignment.

#BRValentine, you are right. Slickgrid grid container element must be given an height (width is optional - by default uses 100% available). If you do not provide an height to the container element, Slickgrid does not render the rows.

specifying the target grid div dimensions solved my problem. This is nowhere in instructions... I'm leaving it here so that others can find it.
<div id="classGrid" style="width:500px; height:600px;"></div>

Related

How can I get rid of the curly bracket from angularjs output and to clear the screen after the display

I thought I finally understand ng-repeat but now I do not know why the output include the curly bracket and how do I clear the screen after reading the output.
Here is part of the output
{"title":"NFL Draft 2020: Over 50 prospects will take part in 'virtual' interviews to air during the event, per report - CBS Sports"}
{"title":"Illinois governor says feds sent wrong type of protective medical masks - CNN"}
but what I really want is just the following without the curly bracket, the word title and the double quotes.
NFL Draft 2020: Over 50 prospects will take part in 'virtual' interviews to air during the event, per report - CBS Sports
and after displaying the list of headlines, I want to clear the screen ( as in "cls" in the command prompt)
my angularjs code is this
$http.post('/disdata', " ").then(function(response) {
$scope.answer = response.data;
var titles = [];
for (var i = 0; i < $scope.answer.length; i++) {
titles.push ({
title: $scope.answer[i].title
});
};
$scope.titles = titles;
console.log($scope.titles);
My html is
<div ng-repeat="(key, value) in titles">
{{value}}
</div>
The syntax you are using is usually used to iterate over properties in an object. Since you already have an array, you can normally iterate over it and display the title value.
angular.module('app', []).controller('Ctrl', ['$scope', ($scope) => {
$scope.titles = [{
"title": "NFL Draft 2020: Over 50 prospects will take part in 'virtual' interviews to air during the event, per report - CBS Sports"
},
{
"title": "Illinois governor says feds sent wrong type of protective medical masks - CNN"
}
];
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<body ng-app="app" ng-controller="Ctrl">
<div ng-repeat="title in titles">
{{title.title}}
</div>
</body>

svg convert to canvas - can't generate multi pages pdf

I have 12 graphs and I want to generate pdf with 2 pages each page has 6 graphs.
However, when I convert svg to canvas, then the jspdf can only see part of both sub-dives.
$('#downloadx2').click(function() {
var svgElements = $("#body_id").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStylex(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
var doc = new jsPDF("p", "mm");
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
html2canvas($("#div_pdf1"), {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/png', 0.1);
doc.addImage(imgData, 'PNG', 5, 0, width, height/2,'','FAST');
doc.addPage();
}
});
html2canvas($("#div_pdf2"), {
onrendered: function(canvas2) {
var imgData2 = canvas2.toDataURL(
'image/png', 0.1);
doc.addImage(imgData2, 'PNG', 5, 0, width, height/2,'','FAST');
doc.save('.pdf');
}
});
});
<body id="body_id">
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
</body>
When I run this code, the generated pdf will view two pages with same canvas the first one (div_pdf1) div. So how to get both of them appearing in pdf as two pages.
You seem to be trying to run 2 parts in sequence but that's not how javascript works and actually runs your code.
No big deal, just a small misunderstanding between your mental model and the engine that executes the code.
A quick temporary debugging tool to see what's going on and verify that there is a discrepancy is to add console.log to key points and check the sequence of their printout once you run the code.
console.log('[1] just before: svgElements.each');
svgElements.each(function() {
console.log('[2] just after: svgElements.each');
And also around this part of the code:
console.log('[3] just before html2canvas-div_pdf1');
html2canvas($("#div_pdf1"), {
console.log('[4] just after html2canvas-div_pdf1');
Finally around this part of the code:
console.log('[5] just before html2canvas-div_pdf2');
html2canvas($("#div_pdf2"), {
console.log('[6] just after html2canvas-div_pdf2');
I suspect you'll see the code doesn't print the log lines in the order you think they will.
Next, you can try wrapping the 2 calls to html2canvas with one setTimeout function and force a delay in the execution of that code by an arbitrary amount of milliseconds.
Note that this is not the recommended final production quality solution but it will make the code output what you want.

SimpleFlip View first image coming back from json doesn't show immediately in winjs

I have a simple WINJS flipview. There are 5 images loaded from an external json file. All the images load immediately except the first one, and second question is there a simple command to automatically set these to rotate?
So we are using a single page model app. This is a little promo slider I wanted to put in on one page and rotate. I've tried everything including just the demo, but the first item always comes back undefined.
I even tried removing the first image, but the first item always comes back undefined. I've spent a few days on this now with not much luck.
<div id="promoTemplate" data-win-control="WinJS.Binding.Template" style="display: none" >
<div class="overlaidItemTemplate">
<img class="image" data-win-bind="src: picture" />
<div class="overlay">
<h2 class="ItemTitle" data-win-bind="innerText: title"></h2>
</div>
</div>
</div>
<div id="promoFlipView" class="flipView" data-win-control="WinJS.UI.FlipView" data-win-options="{ itemDataSource: ActivityPromoData.bindingList.dataSource, itemTemplate: select('#promoTemplate') }">
</div>
This is connected to the demo example flipview Data
//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//// PARTICULAR PURPOSE.
////
//// Copyright (c) Microsoft Corporation. All rights reserved
(function () {
"use strict";
// This is an array that will be used to drive the FlipView in several
// scenarios. The array contains objects with the following attributes:
//
// type - There are two types that are used:
//
// item -
// The type for simple items. It informs the custom
// renderer that their is a title and picture that needs
// to be rendered.
//
// contentsArray -
// This is used for creating a table of contents. It
// informs the renderer that an array of data is present
// for use in constructing the Table of Contents.
//
// title - The title of a photo to be displayed.
//
// picture - The location of the photo to be displayed.
var array = [
{ type: "item", title: "Cliff", picture: "images/Cliff.jpg" },
{ type: "item", title: "Grapes", picture: "images/Grapes.jpg" },
{ type: "item", title: "Rainier", picture: "images/Rainier.jpg" },
{ type: "item", title: "Sunset", picture: "images/Sunset.jpg" },
{ type: "item", title: "Valley", picture: "images/Valley.jpg" }
];
var bindingList = new WinJS.Binding.List(array);
WinJS.Namespace.define("ActivityPromoData", {
bindingList: bindingList,
array: array
});
var e = ActivityPromoData.bindingList.dataSource;
})();
The original question above here is the FIRST IMAGE BUG FIX: adding this to the onready. This works providing there is no custom animations.
var proxyObject;
proxyObject = new WinJS.Binding.as({
itemTemplate: tutorialTemplate,
customAnimations: false
});
tutorialFlipView.winControl.itemTemplate = tutorialTemplate;
There is not builtin command to rotate. setInternval() can be used for this.
var timerId = setInternal(function()
{
if (flipview.winControl.count - 1 == flipview.winControl.currentPage)
flipview.winControl.currentPage = 0;
else
flipview.winControl.next();
}, slideshowInternal);
// to stop slideshow
clearInterval(timerId);
This assumes no complex transition between pages (for example: KENBURNS). if that is required, it is more involved problem, and it is good to consider using some existing javascript sdk on web and integrate in a custom winjs control. flipview control did not work well when integrating custom page transition animations.
regards image not loading - html/js code snippet will help answer it.
if <img> tag is used and bound it to the http image url, image is not guaranteed to be loaded when flipview shows the page. If number of images are handful, it might be better to download them using winjs.xhr to ensure that they are in cache and then, load the flipview.

Template binding with nested for loops WinJS

I've got an issue where I'm using template.render to render an array of items based on a html template. Each item in the array also contains another array, that I want to bind to another template, within the parent element for the area. I know I can use a grid layout for groups, but I'm trying to accomplish this another way, so please, no suggestions to use a different control, I'm just curious as to why the following doesn't work correctly.
//html templates
<div id="area-template" data-win-control="WinJS.Binding.Template">
<h1 class="area-title" data-win-bind="innerHTML:title"></h1>
<div class="items">
</div>
</div>
<div id="item-template" data-win-control="WinJS.Binding.Template">
<h2 class="item-title" data-win-bind="innerHTML:title"></h2>
</div>
// JS in ready event
var renderer = document.getElementsByTagName('section')[0];
var area_template = document.getElementById('area-template').winControl;
var item_template = document.getElementById('item-template').winControl;
for (var i = 0; i < areas.length; i++) {
var area = areas.getAt(i);
area_template.render(area, renderer).done(function (el) {
var item_renderer = el.querySelector('.items');
for (var j = 0; j < area.items.length; j++) {
var item = area.items[j];
item_template.render(item, item_renderer).done(function (item_el) {
});
}
});
}
So what should happen, is that after it renders the area, in the "done" function the newly created element (el) gets returned, I'm then finding it's ".items" div to append the items to. However, this appends all the items to the first div created. If it was the last div, it might make more sense due to closures, but the fact it happens on the first one is really throwing me off!
What's interesting, is that if I replace my template render function using document.createElement and el.appendChild, it does display correctly e.g: (in the done of area render)
area_template.render(area, renderer).done(function (el) {
var item = area.items[j];
var h2 = document.createElement('h2');
h2.innerText = item.title;
el.appendChild(h2);
}
although I've realised this is el it is appending it to, not the actual .items div of the el
I'm not quite sure what could be going on here. It appears the value of el is getting updated correctly, but el.querySelector is either always returning the wrong ".items" div or it's getting retained somewhere, however debugging does show that el is changing during the loop. Any insight would be greatly appreciated.
thanks
I've worked out what is going on here. The "el" returned in the render promise is not the newly created element as I thought. It's the renderer and the newly created html together. Therefore el.querySelector('.items') is always bringing back the first '.items' it finds. I must have misread the docs, but hopefully someone else will find this information useful in case they have the same error.
I guess one way around this would be to do item_rendered = el.querySelectorAll('.items')[i] and return the numbered '.items' based on the position in the loop
e.g
for (var i = 0; i < areas.length; i++) {
var area = areas.getAt(i);
area_template.render(area, renderer).done(function (el) {
var item_renderer = el.querySelectorAll('.items')[i];
for (var j = 0; j < area.items.length; j++) {
var item = area.items[j];
var h2 = document.createElement('h2');
h2.innerText = item.title;
item_renderer.appendChild(h2);
}
});
}

Filtering a page with infinite scroll in AngularJS

I implemented an infinite scrolling feature on my AngularJS + Node.js app.
It is based on this JSfiddle and works the same way: http://jsfiddle.net/vojtajina/U7Bz9/
HTML:
<div id="fixed" when-scrolled="loadMore()">
<ul>
<li ng-repeat="i in items">{{i.id}}</li>
</ul>
</div>​
Javascript:
function Main($scope) {
$scope.items = [];
var counter = 0;
$scope.loadMore = function() {
for (var i = 0; i < 5; i++) {
$scope.items.push({id: counter});
counter += 10;
}
};
$scope.loadMore();
}
angular.module('scroll', []).directive('whenScrolled', function() {
return function(scope, elm, attr) {
var raw = elm[0];
elm.bind('scroll', function() {
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
scope.$apply(attr.whenScrolled);
}
});
};
});
​
My reasons for implementing the infinite scroll is in order to save my users bandwidth by not loading all 1000 results and their corresponding images unless the user wants to see all of it.
However when searching within the results using an AngularJS filter I am encountering problems, because of course not all the results are there (unless the user has scrolled to the very bottom) so the search will only return a fraction of the required results.
I then removed the infinite scrolling feature in order to have the search function work properly but this provided new issues on chrome (not on Firefox though) when I open the page the browser starts loading images from the top. If I then filter the results by searching for something starting with "z" (at the very bottom of the results) Firefox switches focus and loads the results starting with "z" first (as they are then the only ones being displayed). However chrome continues loading through the list and thus the user will only see the results of their search (for "z") once all the images in the app have been loaded.
I am looking for a way to have angular provide both the infinite scroll and a proper search filter on the results at the same time. If this is not possible then a way to make chrome load the visible images first.
I am currently trying some weird stuff with a bunch of different arrays in the scope but I haven't had any luck so far.
Since several people here had a similar issue and I was struggling myself, I took the time to create a fiddle that works (for my case).
https://jsfiddle.net/lisapfisterer/Lu4sbxps/
The main idea is to dynamically extend the limitTo value using infinite-scroll's function call
<div infinite-scroll="loadMore()" infinite-scroll-distance="20">
<tr data-ng-repeat="logEvent in logEventFilter = (logEvents | filter:searchTerm | limitTo:numberToDisplay) track by $index">
<td> {{$index}} </td>
<td> {{logEvent.name}} </td>
<td> {{numberToDisplay}} </td>
</tr>
</div>
loadMore just increases the limit
$scope.loadMore = function() {
if ($scope.numberToDisplay + 5 < $scope.logEvents.length) {
$scope.numberToDisplay += 5;
} else {
$scope.numberToDisplay = $scope.logEvents.length;
}
};
What you want to do isn't "impossible" but it's certainly going to be a little complicated.
Have your server do all of the "filtering" to ensure that the paginated values returned are the proper values for the filter(s).
When the server returns the results, render all of the HTML to the screen except the src attributes of image tags. This way none of the images will begin loading yet.
Scroll to the proper "page".
Make sure all of the heights prior to the images being loaded are the same, now do some JS magic to figure out which ones are visible.
Set the src attribute of the visible images only, Subscribe to their "load" events and create a $q promise that is complete once all loads are complete.
after that promise completes, set the rest of the image src attributes so the remainder of the images will load.

Resources