Datatable update from another component - javascript

I'm using the datatables table plugin for jquery. I have another component that uses Ajax to retrieve an object from the server. I'd like to update the database with this object. I'm struggling on how to piece this together. The Ajax returns an object that is in the format that the datatable will accept for data. But how can I update the datatable from another components Ajax call? I'm using python flask and jinja2 templating. Here is the javascript as it currently exist:
$(function() {
var container = document.getElementById('visualization');
var items = new vis.DataSet({{documents|safe}});
var options = {};
var timeline = new vis.Timeline(container, items, options);
timeline.on('select', function (properties) {
$.getJSON('/getDependencyHistory', {
uuid: properties.items[0]
}, function(data) {
console.log("Place this into the datatable");
});
return false;
});
});
$(document).ready(function() {
var table = $('#example').DataTable();
});

here is a really simple one that "fools" the ajax call.
go to http://live.datatables.net/nesadivo/1/edit
Click on Run With JS button to initialize everything. Click on the go button to go get the data
$(document).ready(function() {
// created a global variable for the datatable to us to find the data
var dtData = null;
// On the button click, use regular ajax to get the data
$("#btnGo").on("click", function(){
$.ajax({url:"http://live.datatables.net/examples/server_side/scripts/server_processing.php",
success:function(cData){
// on success, set the global variable then reload table
dtData = JSON.parse(cData);
$('#example').DataTable( ).ajax.reload();
},
error:function(err){debugger;}} );
});
// initialize the table on page load
$('#example').DataTable( {
"ajax": function(a,callback,c){
callback(dtData);
}
});
});

Related

How to make javascript flow wait till an element is completely rendered

test.view.js
timeDBox = new sap.ui.commons.DropdownBox({layoutData: new sap.ui.layout.GridData({linebreak: true}),
change: function(oEvent){
oController.getKeyEqChart();
},
}),
new sap.ui.core.HTML({
content: "<div id=\"chart1\"></div>",
afterRendering: function(e){
console.log("chart1 create"+timeDBox.getValue());
chart1DivReady = true;
oController.getchart();
}
})
test.controller.js
onInit: function() {
var modelDataEvent = {"genericTableModel":[{"xtime":"1"},{"xtime":"2"},{"xtime":"3"},{"xtime":"4"},{"xtime":"5"},{"xtime":"8"},{"xtime":"10"}]}
var oTemplate11 = new sap.ui.core.ListItem({text : "{xtime}", key : "{xtime}"});
timeDBox.setModel(new sap.ui.model.json.JSONModel(modelDataEvent));
timeDBox.bindItems("/genericTableModel", oTemplate11);
timeDBox.getModel().refresh();
this.getchart();
},
getchart: function(){
var jsonObjToSend = {} ;
jsonObjToSend["dialogue"] = "terminal";
jsonObjToSend["cid"] = "key_equipment ";
var srachmap = {} ;
srachmap["xtime"] = timeDBox.getValue();
jsonObjToSend["search"] = srachmap; this.doAjax("/uri/uri",jsonObjToSend).done(this.updateKeyEqChart);
},
updateKeyEqChart: function(modelData) {
var svg = d3.select("#chart1").append("svg")
1) if i call getchart method from onInit, chart1 id is not created when executing this method
2) if i call getchart chart from oController.getchart() at that time timeDBox.getValue() value is not created which is required to get chart data
},
I am using a drop down list in my application which is populated from database.
Following things happen after the drop down gets populated:
Once the drop down gets populated I use the value of the drop down to render a chart by doing another ajax call to the db.
If the drop down is not populated by the time the flow reaches there then later the chart is not rendered but with time the drop down gets rendered as the ajax where I send param from drop down is null as the drop down is not ready.
So how to make the control wait till the drop down is populated and then go the chart call.
I am not 100% sure that I understand your questions right and the code sample being almost unreadable doesn't help.
But I think onInit might not be the lifecycle hook you are looking for.
If it is a one time deal, I would use onAfterRendering:
onAfterRendering: function() {
// Code
}
If this has to be executed everytime you navigate to this page, then I would add onAfterShow/onBeforeShow delegates in the onInit function.
onInit: function () {
view.addEventDelegate({
/**
* use either or in your case
*/
onAfterShow: function (oEvt) {
// If you use a busy dialog, you want to close it here
},
onBeforeShow: function (oEvt) {
}
});
},
Hope this helps.

How to prevent rebind on kendo grid data item change?

I have a kendo grid, and when an item is selected I want to modify the underlying dataitem so i'm doing this ...
selectionChange: function(e)
{
var component = $(this.table).closest('.component');
var grid = this;
var val = !component.hasClass("secondary");
var selection = grid.dataItems(grid.select());
selection.forEach(function () {
this.set("SaleSelected", val);
});
}
I also have 2 buttons that allow me to push items between the 2 grids which do this ...
select: function (e) {
e.preventDefault();
var sender = this;
// get kendo data source for the primary grid
var source = $(sender).closest(".component")
.find(".component.primary")
.find(".details > [data-role=grid]")
.data("kendoGrid")
.dataSource;
// sync and reload the primary grid
source.sync()
.done(function () {
source.read();
my.Invoice.reloadGridData($(sender).closest(".component").find(".component.secondary").find(".details > [data-role=grid]"));
});
return false;
},
deselect: function (e) {
e.preventDefault();
var sender = this;
debugger;
// get kendo data source for the secondary grid
var source = $(sender).closest(".component")
.find(".component.secondary")
.find(".details > [data-role=grid]")
.data("kendoGrid")
.dataSource;
// sync and reload the primary grid
source.sync()
.done(function () {
source.read();
my.Invoice.reloadGridData($(sender).closest(".component").find(".component.primary").find(".details > [data-role=grid]"));
});
return false;
}
Essentially the "selected items" from grid1 can be marked as such on the server then the grids get reloaded to move the items over.
All good I thought, but apparently Kendo has other ideas.
Editing a data item causes its owning grid to rebind losing the selection state resulting in some confusing behaviour for the user.
Is there a way to tell kendo "i'm going to edit this unbound property right now, don't go messing with binding"?
Ok it turns out kendo is a bit of a wierdo and I still have no idea why they insist you call all their "api stuff" to do simple tasks when doing things more directly actually works better.
In my case I removed the selection change call altogether and let kendo handle that, then in my selection button handlers to move the data between grids I updated the properties directly on the data items instead of calling
"item.set("prop", value)" i now have to do "item.prop = value".
The net result is this ...
select: function (e) {
e.preventDefault();
var sender = this;
// get some useful bits
var component = $(sender).closest(".component");
var primaryGrid = component.find(".component.primary").find(".details > [data-role=grid]").data("kendoGrid");
// get the new selection, and mark the items with val
var selection = $(primaryGrid.tbody).find('tr.k-state-selected');
selection.each(function (i, row) {
primaryGrid.dataItem(row).SaleSelected = true;
primaryGrid.dataItem(row).dirty = true;
});
// sync and reload the primary grid
primaryGrid.dataSource.sync()
.done(function () {
primaryGrid.dataSource.read();
component.find(".component.secondary")
.find(".details > [data-role=grid]")
.data("kendoGrid")
.dataSource
.read();
});
return false;
},
deselect: function (e) {
e.preventDefault();
var sender = this;
// get some useful bits
var component = $(sender).closest(".component");
var secondaryGrid = component.find(".component.secondary").find(".details > [data-role=grid]").data("kendoGrid");
// get the new selection, and mark the items with val
var selection = $(secondaryGrid.tbody).find('tr.k-state-selected');
selection.each(function (i, row) {
secondaryGrid.dataItem(row).SaleSelected = false;
secondaryGrid.dataItem(row).dirty = true;
});
// sync and reload the primary grid
secondaryGrid.dataSource.sync()
.done(function () {
secondaryGrid.dataSource.read();
component.find(".component.primary")
.find(".details > [data-role=grid]")
.data("kendoGrid")
.dataSource
.read();
});
return false;
}
kendo appears to be taking any call to item.set(p, v) as a trigger to reload data so avoiding the kendo wrapper and going directly to the item properties allows me direct control of the process.
Moving the code from the selection change event handler to the button click handler also means i only care about that data being right when it actually needs to be sent to the server, something I just need to be aware of.
I don't like this, but it's reasonably clean and the ui shows the right picture even if the underlying data isn't quite right.
My other option would be to create a custom binding but given that the binding would have to result in different results depending on weather it was binding to the primary or the secondary grid I suspect that would be a lot of js code, this feels like the lesser of 2 evils.
I think you can bind the dataBinding event to just a "preventDefault" and then unbind it and refresh at your leisure
var g = $("#myGrid").data("kendoGrid");
g.bind("dataBinding", function(e) { e.preventDefault(); });
then later...
g.unbind("dataBinding");

Delete rows in Datatable before destroying

I am initializing a Datatable each time the function lds is called. The function lds pulls data for table and appends the relevant HTML by
$('#tablebody').html(data);
After that I am initializing a datatable like so,
$('#rTable').Datatable({
paging:false,
destroy: true
});
This solves the problem of the error "Datatables cannot be initialized" if I call the lds function again. But the old rows are retained that were appended previously. I have tried the following approaches:
Assigned var table to the initialization of Datatable and put table.empty() at the beginning of lds. But as expected, the table variable is undefined.
Tried to delete row(0) while length > 0 but that messes the table and deletes the as well.
Tried ('#rTable').empty() but due to this Datatables throws an error d[i] not defined.
What is an approach I can take to empty the rows each time the function lds is called.
Destroy an existing table on a button click
var table = $('#myTable').DataTable();
$('#tableDestroy').on( 'click', function () {
table.destroy();
} );
Reload a full table description from the server, including columns:
var table = $('#myTable').DataTable();
$('#submit').on( 'click', function () {
$.getJSON( 'newTable', null, function ( json ) {
table.destroy();
$('#myTable').empty(); // empty in case the columns change
table = $('#myTable').DataTable( {
columns: json.columns,
data: json.rows
} );
} );
} );

Backbone.View.model.on('change:...') trigged only once

I'm doing ajax file upload for post via modal window with preview in post. Every post has it's own model and a view. Modal window is also a separate view, binded to existing DOM element.
When Attach button in post view is clicked, I call .open() from modal view, passing post model to modal view as settings:
POST VIEW:
======================
ModalAttach.open({
postModel : this.model
});
When file in modal view is uploaded, I add server response to passed Post model to render it later in post itself as a preview:
MODAL VIEW:
======================
// file upload success
success: function(data) {
// if it's first call, set []
var imagesUploaded = self.postModel.get('images_uploaded') || [];
// add server response to array
imagesUploaded.push(data);
// rewrite current model array to new array
self.postModel.set({ 'images_uploaded' : imagesUploaded });
}
To render preview in post (before real submitting), I've got a function
POST VIEW:
======================
renderUploadedImages: function () {
var self = this;
this.$uploadedImagesWrapper = this.$('.b-uploaded__images');
if (this.model.get('images_uploaded')) {
this.$uploadedImagesWrapper.empty();
this.model.get('images_uploaded').forEach(function (uploadedImage) {
self.$uploadedImagesWrapper.append(
uploadedImageTemplate({
'source': uploadedImage.source
})
)
});
}
}
And to trigger image render, I bind a listner to track when model.images_uploaded is changed by modal view:
POST VIEW:
======================
initialize: function () {
this.addEvents();
this.renderUploadedImages();
},
addEvents: function () {
var self = this;
this.model.on('change:images_uploaded', function () {
self.renderUploadedImages();
})
},
The problem is renderUploadedImages() in Post view is trigged only once, at first upload. Other changes are not caught (when postModel.get('images_uploaded').length becomes 2,3,etc..). What I am doing wrong?
Thanks.
When you do like this :
var imagesUploaded = self.postModel.get('images_uploaded') || [];
// add server response to array
imagesUploaded.push(data);
// rewrite current model array to new array
self.postModel.set({ 'images_uploaded' : imagesUploaded });
The first time, if you check self.postModel.get('images_uploaded') you will find it undefined, that's why when you set it the event change:images_uploaded is triggered.
But the second time you call the success method you don't change the the model attribute, it's always pointing to the same object (array), you just change the array value.
Here's an example

Javascript static variables and using in different pages

I have a jQuery plugin in my layout page header:
<script src="#Url.Content("~/Scripts/js/kendo.web.min.js")"></script>
<script src="#Url.Content("~/Scripts/app/jsCommon.js")"></script>
<script src="#Url.Content("~/Scripts/app/Layout.js")"></script>
and my layout.js:
(function ($) {
var Layout = function (node, options) {
this.node = node;
this.options = $.extend({
url: ""
}, options);
$(this.node).find('.HButton').bind('click', $.proxy(this.HButtonClicked, this));
};
Layout.prototype = {
constructor: Layout,
_loadBackground: function () {
debugger;
//load second now 'Common.currentTarget' have been lost
$(Common.currentTarget).removeClass();
$(Common.currentTarget).addClass(".HButton_Selected");
},
HButtonClicked: function (e) {
debugger;
//load first
Common.currentTarget = e.currentTarget;
}
}
$.fn.Layout = function (options) {
return this.each(function () {
$(this).data('Layout', new Layout(this, options));
});
};
}(jQuery));
in the other side I have a share repository javascript object like this :
function common() {
}
common.currentTarget = null;
var Common = new common();
then in the other page I've triggered an event like following :
<script>
$(document).ready(function () {
var layout = $("#layout").data("Layout");
$(layout).trigger("_loadBackground")
});
</script>
when the HButton element click happened at the first I'm writing the object inside the "Common.currentTarget" and it saved successfully when I've watched variable but when another page loads completely and then trigger the event "_loadBackground" the value of "Common.currentTarget" have been lost, my question is how I can define a static variable like this to be permanent in whole of my pages?
You can set a cookie from javascript to store the data, and then access the cookie from another page. Cookies can persist just during the browser session, or you can give them an expiration. For HTML5, there is local storage.
All JavaScript data is unloaded when the page is changed or refreshed. There is no way around this in JavaScript itself. You will have to send data to the server instead. Probably the easiest way to do this is to store your data in a hidden field:
<input type="hidden" id="storable" />
....
document.getElementById("storable").value = // whatever value you want to store
Then on the server side you can transfer that data to the new page.
If you are redirecting client side, use a query parameter instead.

Categories

Resources