Adding Columns Dynamically to SlickGrid with AJAX. Columns don't show up - dynamic

Using SlickGrid to display some pretty elaborate grids. The Example I am showing here isn't my code but basically an example given by the SlickGrid people duplicating my issue. My Grids need to have columns added dynamically with the column names being fed through an AJAX feed. Creating the column object in JS is not a problem and even adding them using the .push is seems to work fine as I can see them in the firebug console. The new columns never seem to rendner. I get a a bunch of tiny empty cells at the end of the grid but they never populate.
The script below can be replaced with the script in the "example1-simple.html" viewed here.
<script src="../lib/jquery.jsonp-1.1.0.min.js"></script>
<script>
var grid;
var data = [];
var columns = [
{id:"title", name:"Title", field:"title"},
{id:"duration", name:"Duration", field:"duration"},
{id:"%", name:"% Complete", field:"percentComplete"},
{id:"start", name:"Start", field:"start"},
{id:"finish", name:"Finish", field:"finish"},
{id:"effort-driven", name:"Effort Driven", field:"effortDriven"}
];
var dynamicColumns = [];
var options = {
enableCellNavigation: true,
enableColumnReorder: false
};
$(function() {
data = [];
BuildExtraColumnsAJAX();
for (var i = 0; i < 2000; i++) {
data[i] = {
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 == 0)
};
for (var x = 0; x < 20; x++) {
var columnName = "dynamicColumn" + x;
data[i][columnName] = x;
}
}
//alert("Go Pack Go");
grid = new Slick.Grid("#myGrid", data, dynamicColumns, options);
$("#myGrid").show();
})
function BuildExtraColumnsAJAX(){
//dynamicColumns = [];
for (var x = 0; x < columns.length; x++){
dynamicColumns.push(columns[x]);
}
var url = "http://services.digg.com/search/stories? query=apple&callback=C&offset=0&count=20&appkey=http://slickgrid.googlecode.com&type=javascript";
$.jsonp({
url: url,
callbackParameter: "callback",
cache: true, // Digg doesn't accept the autogenerated cachebuster param
success: onSuccess,
error: function(){
alert("BOOM Goes my world");
}
});
}
function onSuccess(resp) {
for (var i = 0; i < resp.stories.length; i++) {
dynamicColumns.push( {
id: "dynamicColumn" + i,
name: "Dynamic Column" + i,
field: "dynamicColumn" + i
});
}
}
function BuildExtraColumns(){
dynamicColumns = [];
for (var x = 0; x < columns.length; x++){
dynamicColumns.push(columns[x]);
}
for (var i = 0; i < 20; i++) {
dynamicColumns.push( {
id: "dynamicColumn" + i,
name: "Dynamic Column" + i,
field: "dynamicColumn" + i
});
}
}
If I put the line grid = new Slick.Grid("#myGrid", data, dynamicColumns, options); in the firebug console and run it the grid than renders fine. It is almost like the script is still executing lines of code even though its not done creating the dynamicColumns.
The Digg AJAX call is just to similute an AJAX call, I of course would be using my own.

The grid is getting initialized before the AJAX call to get the additional columns completes.
Either wait until the columns have loaded to initialize the grid, or update the grid after the additional columns have loaded:
grid.setColumns(dynamicColumns);

Related

In Ionic and Vue.js. How to fetch or “call” data from one file to another?

I’m new to both Ionic and Vue.js. I’m taking advantage of this summer break to start learning both.
I’m building a mobile app for this purpose and so far, so good. However, I have found and issue that I hope you could help me with. Namely, how to fetch or “call” data from one file to another (Is it called routing?).
In my app, I am trying to start/open a function named myFunction() from one of the pages (quiz.vue) when I call it using v-on:click="myFunction3".
This function is located in a JS file called quizz.js, and it is located in the assets folder. This is its path: (“./assets/js/quizz.js”).
I have tried many things to make it work and finally it is working as it should. However, I think my solution is not optimal as it keeps throwing “Uncaught TypeErrors” in the console of the Developer’s Tool…even though it works.
My solution was to push the function inside methods: this.$router.push(myFunction3())
Also, when running the app, it says that myFunction() , and other functions in the same quizz.js file, “is define but never used”.
If you could advise me with anything, I would be most grateful. I am still a beginner so please explain it to me in as simple a manner as possible.
methods:{
openMenu(){
menuController.open("app-menu")
},
myFunction3(){
this.$router.push(myFunction3())
},
Below, the quizz.js file:
var mlhttp = new XMLHttpRequest();
mlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
const quiz = myObj.results[0]['question'];
const correctAnswer = myObj.results[0]['correct_answer'];
const incorrect = myObj.results[0]['incorrect_answers'];
incorrect.push(correctAnswer);
shuffle(incorrect);
document.getElementById("ans").innerHTML = quiz;
var text = "";
var val = 0;
var i;
for (i = 0; i < incorrect.length; i++) {
if(incorrect[i] == correctAnswer){
text += "<ion-button fill='outline' id='right' onClick='increment();myFunc();'/><b>" + incorrect[i] + "</b></ion-button></br>";
val = val + 1;
}else{
text += "<ion-button fill='outline' class='wrong' onClick='myFunc2();'/><b>" + incorrect[i] + "</b></ion-button></br>";
}
}
document.getElementById("ans5").innerHTML = text;
}
};
var j=0;
function myFunction3() {
document.getElementById("ans6").innerHTML = "";
mlhttp.open("GET", "https://opentdb.com/api.php?amount=1", true);
mlhttp.send();
j++;
document.getElementById('ans11').innerHTML=j;
}
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
function myFunc(){
document.getElementById("ans6").innerHTML = "<h1 style='color:green'><i class='fa fa-check'></i> That is correct!</h1>";
document.getElementById("right").style.color = "white";
document.getElementById("right").style.backgroundColor = "green";
var audio = new Audio('./assets/sound/win.mp3');
audio.play();
}
function myFunc2(){
document.getElementById("ans6").innerHTML = "<h1 style='color:red'><i class='fa fa-thumbs-down' ></i>Wrong Answer! </h1>";
document.getElementById("right").style.color = "white";
document.getElementById("right").style.backgroundColor = "green";
var x = document.getElementsByClassName("wrong");
var i;
for (i = 0; i < x.length; i++) {
x[i].style.backgroundColor = "rgba(255, 0, 0, 0.8)";
x[i].style.color = "white";
}
//document.getElementById("wrong").style.color = "red";
var audio = new Audio('./assets/sound/wrong.mp3');
audio.play();
}
var i=0;
function increment() {
i++;
document.getElementById('ans10').innerHTML=i;
}

QZ TRAY PRINITING ORDER NOT IN SEQ

I'm trying to print qz tray from javascript.
I have barcode with number in ascending order 1,2,3,4, 5 and so on.
I looping the seq correctly . but when printed out, it was not in order.
setTimeout("directPrint2()",1000);
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
function directPrint2(){
var data;
var xhttp;
var v_carton = "' || x_str_carton ||'";
var carton_arr = v_carton.split('','');
var v1 = "' ||
replace(x_zebra_printer_id, '\', '|') ||
'".replace(/\|/g,"\\");
if(v1 == ""){
alert("Please setup ZPL Printer");
}
else{
xhttp=new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
data = [ toNative(this.responseText) ];
printZPL(data, v1);
}
};
for (var j = 0; j < carton_arr.length; j++){
var url = "' || x_wms_url ||
'WWW_URL.direct_print_label?in_carton_no="+toValidStr(carton_arr[j]);
xhttp.open("GET", url, false);
xhttp.send();
sleep(5000);
}
}
};
',
'javascript'
What's missing from your example:
I do not see any looping logic in the example calling the printZPL function,
printZPL isn't a QZ Tray function and you're missing the code snippet which it calls. Usually this would be qz.print(config, data);.
Regardless of the missing information, the qz.print(...) API is ES6/Promise/A+ based meaning if you want to call qz.print multiple times in a row you need to use a Promise-compatible technique. (e.g. .then(...) syntax) between your print calls as explained in the Chaining Requests guide.
To avoid this, you can concatenate all ZPL data into one large data array. Be careful not to spool too much data at once.
If you know exactly how many jobs you'll be appending, you can hard-code the promise chain:
qz.websocket.connect()
.then(function() {
return qz.printers.find("zebra"); // Pass the printer name into the next Promise
})
.then(function(printer) {
var config = qz.configs.create(printer); // Create a default config for the found printer
var data = ['^XA^FO50,50^ADN,36,20^FDRAW ZPL EXAMPLE^FS^XZ']; // Raw ZPL
return qz.print(config, data);
})
.catch(function(e) { console.error(e); });
Finally, if you do NOT know in advanced how many calls to qz.print(...) you can use a Promise loop as explained in the Promise Loop guide.
function promiseLoop() {
var data = [
"^XA\n^FO50,50^ADN,36,20^FDPRINT 1 ^FS\n^XZ\n",
"^XA\n^FO50,50^ADN,36,20^FDPRINT 2 ^FS\n^XZ\n",
"^XA\n^FO50,50^ADN,36,20^FDPRINT 3 ^FS\n^XZ\n",
"^XA\n^FO50,50^ADN,36,20^FDPRINT 4 ^FS\n^XZ\n"
];
var configs = [
{ "printer": "ZDesigner LP2844-Z" },
{ "printer": "ZDesigner LP2844-Z" },
{ "printer": "ZDesigner LP2844-Z" },
{ "printer": "ZDesigner LP2844-Z" }
];
var chain = [];
for(var i = 0; i < data.length; i++) {
(function(i_) {
//setup this chain link
var link = function() {
return qz.printers.find(configs[i_].printer).then(function(found) {
return qz.print(qz.configs.create(found), [data[i_]]);
});
};
chain.push(link);
})(i);
//closure ensures this promise's concept of `i` doesn't change
}
//can be .connect or `Promise.resolve()`, etc
var firstLink = new RSVP.Promise(function(r, e) { r(); });
var lastLink = null;
chain.reduce(function(sequence, link) {
lastLink = sequence.then(link);
return lastLink;
}, firstLink);
//this will be the very last link in the chain
lastLink.catch(function(err) {
console.error(err);
});
}
Note: The Promise Loop is no longer needed in QZ Tray 2.1. Instead, since 2.1, an array of config objects and data arrays can be provided instead.

Appcelerator Titanium JS: Table Alphabetical Index not working

I'm trying to get my head around using a the TableView index property to create native right hand alphabetical navigation - similar to that in the Apple iOS Contacts app - shown in the picture below:
I created a really simple example, with a set of rows, with row headers, but it doesn't work - whenever I tap on an index item, it just jumps to the top of the TableView again.
Here is my example code:
// Create the first TableViewSection
var section1 = Ti.UI.createTableViewSection({
headerTitle:'A'
});
// use a loop to add some rows
for (var i=0; i < 20; i++) {
section1.add(Ti.UI.createTableViewRow({
title:'Row '+i
}));
}
// do it all again...
var section2 = Ti.UI.createTableViewSection({
headerTitle: 'B'
});
for (var i=4; i < 10; i++) {
section2.add(Ti.UI.createTableViewRow({
title:'Row '+i
}));
}
// Now, here's our table, and we're setting the data to hold the sections
var tv = Ti.UI.createTableView({
data:[section1,section2]
});
// Create a table view index
var index = [
{ title: "A", index: 0 },
{ title: "B", index: 1 }
];
// Set the index on the table view
tv.setIndex(index);
$.index.open();
$.index.add(tv);
Here is an example for you dear
var win = Ti.UI.createWindow();
var table = Ti.UI.createTableView({});
var contacts = ["Adam", "Andrew", "Boris", "Claus", "Debby", 'Saba', 'Sana', 'Wahhab', 'Zohaib', 'Zzaid', 'Zzxad'];
var curheader = 'A';
var sectionArr = [];
var index = [];
for (var i = 0, lastL, l, currSection, ilen = contacts.length; i < ilen; i++) {
l = contacts[i].substr(0, 1);
if (lastL != l) {
index.push({
title : l,
index : i
});
currSection = Ti.UI.createTableViewSection({
headerTitle : l
});
sectionArr.push(currSection);
}
currSection.add(Ti.UI.createTableViewRow({
title : contacts[i],
}));
lastL = l;
}
table.setData(sectionArr);
table.index = index;
win.add(table);
win.open();
Thanks

Creating dynamic number of select based on entered textbox value

I have a javascript which when a user enters a number to textbox,the script generates that much number of textboxes dynamically.But what i need is to create is select's instead of textboxes with options retrieved from mysql database.
the javascript for creating textbox is given below,
<script type="text/javascript" >
$(document).ready(function () {
$("#stops").change(function () {
var count = $("#holder input").size();
var requested = parseInt($("#stops").val(), 10);
if(requested == 0 && count > 0){
location.reload();
}
$("#title").html("Stop Codes");
if (requested > count) {
for (i = count; i < requested; i++) {
var $ctrl = $('<input/>').attr({
type: 'text',
name: 'text' + i,
placeholder: "Enter stop " +(i+1) +" airport code"
});
$("#holder").append($ctrl);
}
} else if (requested < count) {
var x = requested - 1;
$("#holder input:gt(" + x + ")").remove();
}
});
});
HTML generated textboxes here
<td id="holder"></td>

Cannot dynamically change a caption 'track' in Video.js

I'm coding a basic video marquee and one of the key requirements is that the videos need to be able to advance while keeping the player in full screen.
Using Video.js (4.1.0) I have been able to get everything work correctly except that I cannot get the captions to change when switching to another video.
Either inserting a "track" tag when the player HTML is first created or adding a track to the 'options' object when the player is initialized are the only ways I can get the player to display the "CC" button and show captions. However, I cannot re-initialize the player while in full screen so changing the track that way will not work.
I have tried addTextTrack and addTextTracks and both show that the tracks have been added - using something like console.log(videoObject.textTracks()) - but the player never shows them or the "CC" button.
Here is my code, any help is greatly appreciated:
;(function(window,undefined) {
// VIDEOS OBJECT
var videos = [
{"volume":"70","title":"TEST 1","url":"test1.mp4","type":"mp4"},
{"volume":"80","title":"TEST 2","url":"test2.mp4","type":"mp4"},
{"volume":"90","title":"TEST 3","url":"test3.mp4","type":"mp4"}
];
// CONSTANTS
var VIDEO_BOX_ID = "jbunow_marquee_video_box", NAV_TEXT_ID = "jbunow_marquee_nav_text", NAV_ARROWS_ID = "jbunow_marquee_nav_arrows", VIDEO_OBJ_ID = "jbunow_marquee_video", NAV_PREV_ID = "jbunow_nav_prev", NAV_NEXT_ID = "jbunow_nav_next";
// GLOBAL VARIABLS
var videoObject;
var currentTrack = 0;
var videoObjectCreated = false;
var controlBarHideTimeout;
jQuery(document).ready(function(){
// CREATE NAV ARROWS AND LISTENERS, THEN START MARQUEE
var navArrowsHtml = "<div id='" + NAV_PREV_ID + "' title='Play Previous Video'></div>";
navArrowsHtml += "<div id='" + NAV_NEXT_ID + "' title='Play Next Video'></div>";
jQuery('#' + NAV_ARROWS_ID).html(navArrowsHtml);
jQuery('#' + NAV_PREV_ID).on('click',function() { ChangeVideo(GetPrevVideo()); });
jQuery('#' + NAV_NEXT_ID).on('click',function() { ChangeVideo(GetNextVideo()); });
ChangeVideo(currentTrack);
});
var ChangeVideo = function(newIndex) {
var videoBox = jQuery('#' + VIDEO_BOX_ID);
if (!videoObjectCreated) {
// LOAD PLAYER HTML
videoBox.html(GetPlayerHtml());
// INITIALIZE VIDEO-JS
videojs(VIDEO_OBJ_ID, {}, function(){
videoObject = this;
// LISTENERS
videoObject.on("ended", function() { ChangeVideo(GetNextVideo()); });
videoObject.on("loadeddata", function () { videoObject.play(); });
videoObjectCreated = true;
PlayVideo(newIndex);
});
} else { PlayVideo(newIndex); }
}
var PlayVideo = function(newIndex) {
// TRY ADDING MULTIPLE TRACKS
videoObject.addTextTracks([{ kind: 'captions', label: 'English2', language: 'en', srclang: 'en', src: 'track2.vtt' }]);
// TRY ADDING HTML
//jQuery('#' + VIDEO_OBJ_ID + ' video').eq(0).append("<track kind='captions' src='track2.vtt' srclang='en' label='English' default />");
// TRY ADDING SINGLE TRACK THEN SHOWING USING RETURNED ID
//var newTrack = videoObject.addTextTrack('captions', 'English2', 'en', { kind: 'captions', label: 'English2', language: 'en', srclang: 'en', src: 'track2.vtt' });
//videoObject.showTextTrack(newTrack.id_, newTrack.kind_);
videoObject.volume(parseFloat(videos[newIndex]["volume"]) / 100); // SET START VOLUME
videoObject.src({ type: "video/" + videos[newIndex]["type"], src: videos[newIndex]["url"] }); // SET NEW SRC
videoObject.load();
videoObject.ready(function () {
videoObject.play();
clearTimeout(controlBarHideTimeout);
controlBarHideTimeout = setTimeout(function() { videoObject.controlBar.fadeOut(); }, 2000);
jQuery('#' + NAV_TEXT_ID).fadeOut(150, function() {
currentTrack = newIndex;
var navHtml = "";
navHtml += "<h1>Now Playing</h1><h2>" + videos[newIndex]["title"] + "</h2>";
if (videos.length > 1) { navHtml += "<h1>Up Next</h1><h2>" + videos[GetNextVideo()]["title"] + "</h2>"; }
jQuery('#' + NAV_TEXT_ID).html(navHtml).fadeIn(250);
});
});
}
var GetPlayerHtml = function() {
var playerHtml = "";
playerHtml += "<video id='" + VIDEO_OBJ_ID + "' class='video-js vjs-default-skin' controls='controls' preload='auto' width='560' height='315'>";
playerHtml += "<source src='' type='video/mp4' />";
//playerHtml += "<track kind='captions' src='track.vtt' srclang='en' label='English' default='default' />";
playerHtml += "</video>";
return playerHtml;
}
var GetNextVideo = function() {
if (currentTrack >= videos.length - 1) { return 0; }
else { return (currentTrack + 1); }
}
var GetPrevVideo = function() {
if (currentTrack <= 0) { return videos.length - 1; }
else { return (currentTrack - 1); }
}
})(window);
The current VideoJS implementation (4.4.2) loads every kind of text tracks (subtitles, captions, chapters) on initialization time of the player itself, so it grabs correctly only those, which are defined between the <video> tags.
EDIT: I meant it does load them when calling addTextTrack, but the player UI will never update after initialization time, and will always show the initialization time text tracks.
One possible workaround is if you destroy the complete videojs player and re-create it on video source change after you have refreshed the content between the <video> tags. So this way you don't update the source via the videojs player, but via dynamically adding the required DOM elements and initializing a new player on them. Probably this solution will cause some UI flashes, and is quite non-optimal for the problem. Here is a link about destroying the videojs player
Second option is to add the dynamic text track handling to the existing code, which is not as hard as it sounds if one knows where to look (I did it for only chapters, but could be similar for other text tracks as well). The code below works with the latest official build 4.4.2. Note that I'm using jQuery for removing the text track elements, so if anyone applies these changes as is, jQuery needs to be loaded before videojs.
Edit the video.dev.js file as follows:
1: Add a clearTextTracks function to the Player
vjs.Player.prototype.clearTextTracks = function() {
var tracks = this.textTracks_ = this.textTracks_ || [];
for (var i = 0; i != tracks.length; ++i)
$(tracks[i].el()).remove();
tracks.splice(0, tracks.length);
this.trigger("textTracksChanged");
};
2: Add the new 'textTracksChanged' event trigger to the end of the existing addTextTrack method
vjs.Player.prototype.addTextTrack = function(kind, label, language, options) {
...
this.trigger("textTracksChanged");
}
3: Handle the new event in the TextTrackButton constructor function
vjs.TextTrackButton = vjs.MenuButton.extend({
/** #constructor */
init: function(player, options) {
vjs.MenuButton.call(this, player, options);
if (this.items.length <= 1) {
this.hide();
}
player.on('textTracksChanged', vjs.bind(this, this.refresh));
}
});
4: Implement the refresh method on the TextTrackButton
// removes and recreates the texttrack menu
vjs.TextTrackButton.prototype.refresh = function () {
this.removeChild(this.menu);
this.menu = this.createMenu();
this.addChild(this.menu);
if (this.items && this.items.length <= this.kind_ == "chapters" ? 0 : 1) {
this.hide();
} else
this.show();
};
Sorry, but for now I cannot link to a real working example, I hope the snippets above will be enough as a starting point to anyone intrested in this.
You can use this code when you update the source to a new video. Just call the clearTextTracks method, and add the new text tracks with the addTextTrack method, and the menus now should update themselves.
Doing the exact same thing (or rather NOT doing the exact same thing)... really need to figure out how to dynamically change / add a caption track.
This works to get it playing via the underlying HTML5, but it does not show the videojs CC button:
document.getElementById("HtmlFiveMediaPlayer_html5_api").innerHTML = '<track label="English Captions" srclang="en" kind="captions" src="http://localhost/media/captiontest/demo_Brian/demo_h264_1.vtt" type="text/vtt" default />';