DataTables - Column render call twice - datatables

I'm very new to Datatables plugin and i'm using it for my small project. I have the following problem like this:
+ I want to create a table and each row have a link to pop up a modal for editing.
Currently my datatables implementation as follow:
$(document).ready(function () {
$('#dtTable').DataTable({
serverSide: false,
processing: true,
deferRender: true,
ajax: {
type: 'POST',
url: '#Url.Action("GetClasses", "CLASSes")',
dataSrc: ""
},
columns: [
{ data: 'CLASSID' },
{ data: 'CLASSCODE' },
{ data: 'CLASSNAME' },
{
orderable: false,
searchable: false,
render: function (data, type, full, meta) {
debugger;
var data = full.CLASSID;
return 'Action';
}
}
]
});
})
The problem is that when ever i click on the Action link the modal will appear and then disappear instantly, place a debugger at the render section it's seemed that this section call twice and i don't know why?
So please help me to achieve this, each row has its link to pop up a modal and when click on it.
Thanks you guys very much

jQuery DataTables plug-in indeed calls render multiple times: for data type detection, display, sorting, etc.
Use the following code to produce content for display only:
render: function (data, type, full, meta) {
if(type === 'display'){
data = 'Action';
}
return data;
}
Regarding modal dialogs, most likely there is a problem somewhere else in your code that makes the modal dialog disappear.

Related

Data is not updated in Vue component when emit calls function

Note: when I upload small size image then the data refreshes and if the image is bigger like 1 mb then it doesn't refresh the data.
I have a add new product modal and when I open it as below:
<NewProduct v-if="showNewProduct" #close-modal="showNewProductModal" #success="showSuccessAlert"/>
and when I add the product and the modal is closed by emitting as below:
Products.addProduct(form)
.then(
this.$emit("closeModal"),
this.$emit("success"),
)
Then in the parent component the data is not refreshed and show the old data and if I refresh the page then it show the new data.
I get data as below in parent component:
data: function () {
return {
showNewProduct: false,
productList: [],
success: false,
};
},
mounted() {
this.getProductList();
},
methods:{
showSuccessAlert() {
this.getProductList(),
this.success = !this.success,
},
showNewProductModal() {
this.showNewProduct = !this.showNewProduct;
},
getProductList() {
User.getProductList()
.then((response) => {
this.productList = response.data;
});
},
}
My goal is that when the modal is closed then the productList should be updated as well with the newly added data without page refresh.
Add product API.
addProduct(form) {
return Api().post("/addProduct", form);
},
It is something related to asynchronous processing. Please, make sure you start fetching record only after the upload is completed.
Products.addProduct(form).then(() => { this.$emit("closeModal")} )
showNewProductModal() { this.getProductList()}
Products.addProduct(form).then(({data: product}) => {
//pass data to close model event
this.$emit("closeModal", product),
this.$emit("success"),
}
showNewProductModal(product) {
this.productList.push(product);
this.showNewProduct = !this.showNewProduct;
}

Codemirror does not refresh the contents of the textarea until its clicked or if I use the JSON.parse on the contents while setting

I am developing a web application using Vuejs/Nuxtjs within that I have some textarea which is controlled by CodeMirror for beautification purposes. The problem I am facing is that when the content of the CodeMirror changes then it is not reflected on the CodeMirror textarea unless I click on it or if I use the JSON.parse while setting the value in Watch. If I click on it then it reflects the changes and everything is correctly working.
Following is the textarea which is governed by CodeMirror:
<textarea
ref="input"
:value="$store.state.modules.MyModules.input"
class="form-control"
placeholder="Input"
spellcheck="false"
data-gramm="false"
/>
Following is the code sample where I am loading the contents to CodeMirror if the values changes using the Vuejs Watch function:
data () {
return {
inputEditor: null
}
},
watch: {
'$store.state.modules.MyModules.input' (value) {
if (value !== this.inputEditor.getValue()) {
this.inputEditor.setValue(value)
}
}
},
mounted () {
this.inputEditor = CodeMirror.fromTextArea(this.$refs.testInput, {
mode: "applicaton/ld+json",
beautify: { initialBeautify: true, autoBeautify: true },
lineNumbers: true,
indentWithTabs: true,
autofocus: true,
tabSize: 2,
gutters: ["CodeMirror-lint-markers"],
autoCloseBrackets: true,
autoCloseTags: true,
styleActiveLine: true,
styleActiveSelected: true,
autoRefresh: true,
});
// On change of input call the function
this.inputEditor.on("change", this.createTestData);
// Set the height for the input CodeMirror
this.inputEditor.setSize(null, "75vh");
// Add the border for all the CodeMirror textarea
for (const s of document.getElementsByClassName("CodeMirror")) {
s.style.border = "1px solid black";
}
}
I found issues similar to this and tried the following things but still no luck:
Trying to refresh the contents within the watch method:
watch: {
'$store.state.modules.MyModules.input' (value) {
const vm = this
if (value !== this.inputEditor.getValue()) {
this.inputEditor.setValue(value)
setTimeout(function () {
vm.inputEditor.refresh()
}, 1)
}
}
},
Trying to use the autorefresh within my CodeMirror but that also did not work.
What worked for me is that when setting the value I need to use the JSON.parse within the watch method. If I do that then It's working correctly but I do not want to do that:
watch: {
'$store.state.modules.MyModules.input' (value) {
const vm = this
if (value !== this.inputEditor.getValue()) {
this.inputEditor.setValue(JSON.parse(value))
}
}
},
Can someone please inform me why the CodeMirror data will not be updated if I do not do JSON.parse?
Chain this to the master codemirror object, make sure nothing else is chained:
.on('change', editor => {
globalContent = editor.getValue();
});;
Providing the answer as it can be helpful to someone else in the future:
Actually the vm.inputEditor.refresh() will work only problem was that I was using it with setTimeout 0.001s which is way to quick for to refresh.
After trying a lot I found my stupid mistake. I tried to change it to 1000 or 500 and it works now.
Following is the change:
setTimeout(function () {
vm.inputEditor.refresh()
}, 1000)

Datatables AJAX.reload Callback data

When using Datatables (Ver: 1.10.16), I noticed that the data in the API is not updated immediately via ajax.reload in the callback even though the site says the callback is not called until the new data has arrived and been redrawn.
Notes up front:
All the data is formatted correctly and displays in the table before and after the ajax.reload, including the new data from the reload.
If I click reload twice, the api sees the new data properly and ApplyHeaderFilters works properly.
When I say the API seeing the data properly I mean like so:
$('#dtTbl').DataTable().column('1:visible').data().unique()
The ApplyHeaderFilters is the callback on ajax.reload and uses the above JS command to get unique values from the column. The data returned from the JS command are not reflecting the new data that is returned from the reload.
This is in the Document Ready:
batchDT = $('#dtTbl').DataTable( {
deferLoading: true,
pageLength: 25,
pagingType: 'simple_numbers',
scrollx: true,
initComplete: function () {
ApplyHeaderFilters($(this).attr('id'), this.api());
},
ajax: {
url: "mysite.cfm?method=gettabledata",
type: 'POST'
},
columns: [
{ title: "Description", name: "description", data: "description"},
{ title: "Is Active", name: "isactive", data: "isactive"},
{ title: "List Item ID", name: "listitemid", data: "listitemid"},
{ title: "Name", name: "name", data: "name"},
{ title: "Table Ref ID", name: "tablerefid", data: "tablerefid", orderable: false}
]
} );
$("#reload").on('click',function(){
batchDT.ajax.reload(ApplyHeaderFilters('dtTbl', $('#dtTbl').DataTable()));
});
For some reason the callback was being called before the reload was completed. I fixed this by wrapping my callback function in reload in an anon function. If anyone has ideas why this would be this way comment please. I have a feeling it has something to do with closures and how they are handling the callback in the datatables library.
$("#reload").on('click',function(){
batchDT.ajax.reload(function(){
ApplyHeaderFilters('dtTbl', $('#dtTbl').DataTable());
});
});

Why it is hard to use vue-i18n in vue data() (why it is not reactive)

I am using vue-i18n in a vue project. And I found it really confusing when using some data in vue data with i18n. Then if I change locale, that data is not reactive. I tried to return that data from another computed data but anyways it is not reactive because i18n is written in data. *My situation - * I want to show table with dropdown(list of columns with checkbox) above it. When user checks a column it will be showed in table if unchecks it won't. It is working fine until I change locale. After changing locale table columns is not translated but dropdown items is reactively translated and my code won't work anymore. Here is some code to explain better: In my myTable.vue component I use bootstrap-vue table -
template in myTable.vue
<vs-dropdown vs-custom-content vs-trigger-click>
<b-link href.prevent class="card-header-action btn-setting" style="font-size: 1.4em">
<i class="fa fa-th"></i>
</b-link>
<vs-dropdown-menu class="columns-dropdown">
<visible-columns :default-fields="columns" #result="columnListener"></visible-columns>
</vs-dropdown-menu>
</vs-dropdown>
<b-table class="generalTableClass table-responsive" :fields="computedFieldsForTable">custom content goes here</b-table>
script in myTable.vue
data(){
return {
fieldsForTable: [];
}
},
computed: {
computedFieldsForTable () {
return this.fieldsForTable;
},
columns() {
return [
{
key: 'id',
label: this.$t('id'),,
visible: true,
changeable: true
},
{
key: 'fullName',
label: this.$t('full-name'),,
visible: true,
changeable: true
},
{
key: 'email',
label: this.$t('email'),,
visible: true,
changeable: true
}
]
}
},
mounted () {
this.fieldsForTable = this.filterColumns(this.columns);
},
methods: {
filterColumns(columns = []) {
return columns.filter(column => {
if (column.visible) {
return column
}
})
},
columnListener ($event) {
this.fieldsForTable = this.filterColumns($event)
}
}
Can someone give me some advice for this situation ?
*EDIT AFTER SOME DEBUGGING: I think when filtering columns(in computed) and returning it for fieldsForTable inside filterColumns(columns) method, it actually returning array(of objects) with label='Label Name' not label=this.$t('labelName'). So after filtering the new array has nothing to do with vue-i18n. My last chance is reloading the page when locale changes.
Trying modify computedFieldsForTable as follows. You need to reference this.columns in computedFieldsForTable, so that Vue can detect the change of labels in this.columns.
computedFieldsForTable () {
return this.filterColumns(this.columns);
},
EDITED: put your this.columns in data. Then
columnListener ($event) {
this.columns = $event;
}
I hope i didn't misunderstand what you mean.
EDITED (again):
Maybe this is the last chance that I think it can work. Put columns in computed() still and remove computedFieldsForTable. Finally, just leave fieldsForTable and bind it on fields of <b-table>.
watch: {
columns(val) {
this.fieldsForTable = this.filterColumns(val)
}
},
method: {
columnListener ($event) {
this.fieldsForTable = this.filterColumns($event)
}
}
However, I think it is better and easier to reload page whenever local change. Especially when your columns have a more complex data structure.

Loading indicator on store loading

My store is taking time to load.so that i want to display a loading indicator while loading store data.Is there any function to know the list store is completely loaded or not?
Please help me..I was searching for this long time..
Here is my code:
Ext.Viewport.setMasked({
xtype: 'loadmask',
message: 'Loading'
});
Ext.define('MyApp.view.Myview1',
{
extend: 'Ext.Panel',
requires: ['Ext.List', 'Ext.util.JSON'],
config: {
layout: 'hbox',
items: [
{
xtype: 'panel',
layout: 'fit',
flex: 1,
items: [
{
xtype: 'list',
itemTpl:
'<div class="myContent">' +
'<div>{name}</div>' +
'</div>',
store: 'MainStore',
disclosure: true,
store.on({
load: {
fn: function( store ) {
Ext.Viewport.setMasked(false);
},
scope: this,
single: true
}
});
store.load();
}
]
}
]
}
});
My requirement is to display indicator while loading data from store and remove it after the list have all data from store.
You will have to bind load event to this store like below code
Ext.Viewport.setMasked({
xtype: 'loadmask',
message: 'Loading'
});
store.on({
load: {
fn: function( store ) {
Ext.Viewport.setMasked(false);
},
scope: this,
single: true
}
});
store.load();
This one is simple, just like #Naresh Said
put load mask inside your function
Ext.Viewport.setMasked({
xtype: 'loadmask',
message: 'Please Wait...'
});
and disable loadmask after store loads
storectn.load({
callback: function (records, operation, success, response) {
if (success==1) {
// Ext.Msg.alert('success');
Ext.Viewport.setMasked(false);
} else {
// Ext.Msg.alert('Failed');
Ext.Viewport.setMasked(false);
}
}
});
Finally I have solved the problem :)
Sencha loads the store and list within a very short time but the UI takes long time to load. So, after finish loading the stores if you set a callback to remove indicator using setTimeout then the problem will be solved. Because when UI loading is finished it will call your final method, because JavaScript is a single thread language.
Ext.Viewport.setMasked({
xtype: 'loadmask',
message: 'Loading'
});
store.on({
load: {
fn: function( store ) {
setTimeout(function(){
Ext.Viewport.setMasked(false);
}, 100);
},
scope: this,
single: true
}
});
store.load();
Here even though the setTimeout is supposed to be called after 100 milliseconds, it will wait for the UI to be loaded first and then be called.
If you are loading the store dynamically by a custom query with store.add(Record), then after loading all data you just call the setTimeout call. It will work as well.
We need to setmask(prevent user interaction and show loading message) while loading data in sencha touch. Sencha touch setMasked(<>) gives option to add mask into containers. But every time we need to manually add the mask and remove the mask. Instant of this manually doing things we can use store listeners.
My requirement here is i have a one store for CRUD process. So every time when i try to sync and loading the data’s i want to setmask of the view. My store code is like the below.
I used beforeload, beforesync, load, metachange, removerecords, updaterecord, write, addrecords events for this task.
Please visit the below url for full source code by clicking the link. [Solved by solution]
http://saravanakumar.org/blog/2014/04/sencha-touch-setmask-display-load-mask-or-waiting-while-loading-data-in-store/