Assign object {row} to state - react-bootstrap-table

I'm trying to migrate my application which currently uses react-bootstrap-table to react-bootstrap-table-next but I'm having a problem.
What I am trying to do:
is to get the object of the selected line.
My code
const selectRow = {
mode: 'radio',
hideSelectColumn: true,
clickToSelect: true,
bgColor: 'red',
onSelect: (row) => {
console.log(row)
}
};
<div className="col-lg-12">
<BootstrapTable keyField='id' data={ products } columns={ columns } selectRow={ selectRow } />
</div>
result obtained
When I click on the line, it assigns the color red and prints the object to the selected line
but when I try to put the object in the state:
const selectRow = {
mode: 'radio',
hideSelectColumn: true,
clickToSelect: true,
bgColor: 'red',
onSelect: (row) => {
console.log(row)
this.setState({banco: row});
}
};
The selected line object is assigned to {banco} property as expected, but the line does not turn red.

I think you need to check this. As the above link mention, right now there's only one workaround is when you need to call setState in selectRow.onSelect, please also manage the selection by yourself via selectRow.selected I'm the creator of react-bootstrap-table and we will improve this issue in the future. Please follow above link to have a workaround, thanks

Related

Vue state does not sync with kendo datasource

I have a kendo wrapper grid with local kendo datasource pointing to vue state.
There is a button "Update" which will update the state so that the grid will be updated as well and it works.
But if I firstly click the button "Test" (just only a same value assignment to state) and then click "Update", strangely it does not work so the grid has no change.
I finally found out the reason is that after clicked "Test" then "Update", the vue state updated but the kendo grid datasource won't (out of sync unexpectedly).
Now the temp solution is I have to manually assign the state to the datasource so that the grid will be updated.
Repo: http://dojo.telerik.com/aGENIHuW
My question is why, after clicked 'Test', the kendo grid datasource became cached and out of sync with the vue state?
If I don't click 'Test', they do sync always.
Problem occur only when "same value assignment" to the state. If "different value assignment", no problem.
<div id="vueapp">
<kendo-datasource ref="dsDS" :data="localDataSource"></kendo-datasource>
<kendo-grid :data-source-ref="'dsDS'">
<kendo-grid-column :field="'ProductID'"
:title="'ID'"
:width="40"></kendo-grid-column>
<kendo-grid-column :field="'ProductName'"></kendo-grid-column>
<kendo-grid-column :field="'UnitPrice'"
:title="'Unit Price'"
:width="120"
:format="'{0:c}'"></kendo-grid-column>
<kendo-grid-column :field="'UnitsInStock'"
:title="'Units In Stock'"
:width="120"></kendo-grid-column>
<kendo-grid-column :field="'Discontinued'" :width="120"></kendo-grid-column>
</kendo-grid>
<input type="button" value="Test" #click="test" />
<input type="button" value="Update" #click="update" />
</div>
new Vue({
el: '#vueapp',
data: {
localDataSource: [{
"ProductID": 1,
"ProductName": "Chai",
"UnitPrice": 18,
"UnitsInStock": 39,
"Discontinued": false,
},
{
"ProductID": 2,
"ProductName": "Chang",
"UnitPrice": 17,
"UnitsInStock": 40,
"Discontinued": false,
},
{
"ProductID": 3,
"ProductName": "Aniseed Syrup",
"UnitPrice": 10,
"UnitsInStock": 13,
"Discontinued": false,
}
]
},
methods: {
test: function(e) {
this.localDataSource = JSON.parse(JSON.stringify(this.localDataSource)); //same value assignment
console.log('test');
},
update: function(e) {
this.localDataSource.splice(0, 1, this.localDataSource[1]); //replace the first object with second object
},
}
})
Update:
Let me emphasize my question below:
Why test2() + update() => Works!
But test() + update() => NOT work
Their different is just the value assignment 'hello' for test2()
methods: {
test: function(e) { //same value assignment
let ds = JSON.parse(JSON.stringify(this.localDataSource));
this.localDataSource = JSON.parse(JSON.stringify(ds));
},
test2: function(e) { //different value assignment
let ds = JSON.parse(JSON.stringify(this.localDataSource));
ds[0]['ProductName'] = 'hello';
this.localDataSource = JSON.parse(JSON.stringify(ds));
},
update: function(e) {
this.localDataSource.splice(0, 1, this.localDataSource[1]); //replace first row with second row
}
}
http://dojo.telerik.com/aGENIHuW/10
Once the datasource is set in the data() object, and the kendo grid is bound, I wouldn't try to edit the localDataSource object. The kendo grid gets your basic array and converts it into a kendo datasource with all the extended properties, so I would target that new object to make changes.
try something like below in your update method - if you can assign the grid an id through a wrapper attribute then the selector would be better than what i have here
let gridDS = $("div[data-role=grid]").data("kendoGrid").dataSource;
let data = gridDS.data();
data.splice(0,1,data[1]);
btw the data method should return a new object otherwise you might have issues with duplicate components sharing the same object
so instead of
data:{
localDataSource:[1,2,3]
}
i would do
data(){
return {
localDataSource:[1,2,3]
}
}
Adding this as answer because comments won't accommodate this much text:
If you do a data dump after the update() function:
console.table(this.localDataSource)
you will see that the localDataSource array is being updated correctly. But the kendo grid isn't aware of it. It still has its own array of data. If you do a corresponding dump of the kendo data source, you will see it has not been synced
let gridDS = $("div[data-role=grid]").data("kendoGrid").dataSource;
let data = gridDS.data();
console.table(data);
What I think is happening is this - since localDataSource is a property of data(), Vue observes any changes to its nested properties.
When it executes code ds[0]['ProductName'] = 'hello' Vue picks up the update, looks for dependencies on the object, and rebinds the kendo-grid component.

How to Fetch data to dynamically build out a custom Menu for a Layout?

What I would like to do is, call an endpoint to get the list of categories to display in the Sidebar's Menu. I'm not seeing anything in the Layout that would handle this. Am I missing something? What would be the correct way to do this?
Thanks #François, good to know I don't need to look any further in the Layout or Menu files.
Looking at the Demo source code, I see this approach in action using Reacts useState and useEffect.
Posted for others, this is in my Admin component:
const [categories, setCategories] = useState({categories: []});
useEffect(
() => {
dataProvider.getList('tools', {
sort: '',
pagination: {
page: 1,
perPage: 10
}
}).then(data =>
setCategories({categories: data['data']}))
},
[]
);

Custom Message or paragraph from the using Jquery datatable and pdf export

I'm using the pdf button from jquery datatables which is essentially the pdfmake library. The problem that I'm having is that I would like to add an additional paragraph right above my table when the user clicks the button to export the table. I have tried using the "message" parameter but for the life of me I cannot retrieve additional information right before the pdf will download. I tried doing this.
buttons: [
{
extend: 'pdfHtml5',
orientation: 'landscape',
pageSize: 'LEGAL',
title: 'Entry',
header:true,
message:function() { $("#HeaderDesc").text()}
}
]
But I have been unsuccessful in my attempts. Does anyone have any ideas on how to accomplish this?
There is another easy solution to this.
I accomplished this by using splice property. You can do like this inside customize function.
doc.content.splice(0, 1, {
text: [
{ text: 'I am loving dataTable and PdfMake \n',bold:true,fontSize:15 },
{ text: 'You can control everything.',italics:true,fontSize:12 }
],
margin: [0, 0, 0, 12],
alignment: 'center'
});
This will splice at the first position [0 index] as well as replace 1 value with the above content.
Happy coding!!!!
You cannot. The config literal for the button is read once, and message does not support function type.
However, you can change the message in the not so well documented customize() callback. This is called just before dataTables pass the generated document to pdfmake. If you have defined a message, then there will exists message section(s) in the content nodes, and those nodes have a text attribute holding the actual message :
customize: function ( doc ) {
doc.content.forEach(function(content) {
if (content.style == 'message') {
content.text = 'this is a late created message'
}
})
}
As mentioned, you must define message before this will work. If you have not defined message, there will be no styles of type message you can manipulate. Your pdfhtml5 settings could look like this :
buttons: [
{
message: '__MESSAGE__',
extend: 'pdfHtml5',
orientation: 'landscape',
pageSize: 'LEGAL',
title: 'Entry',
header:true,
customize: function ( doc ) {
doc.content.forEach(function(content) {
if (content.style == 'message') {
content.text = $("#HeaderDesc").text()
}
})
}
}
]
demo -> https://jsfiddle.net/xx5f5z6x/

canvasOverlay show in jqplot

How do I trigger on the overlays in jqplot only after I click a checkbox (not when the html loads). When I first set overlay option show to false the overlays are not displayed on plot at 1st and when I used my trigger function the overlays do not appear.
Here is the code I use for the plot :
<div id="fastest" style="margin-top:20px; margin-left:20px; margin-right:200px; width:800px; height:400px;">
<script class="code" type="text/javascript">
$(document).ready(function(){
var dataset="too long to be displayed here"
plot1 = $.jqplot('fastest', dataset, {
title: 'Test_figs',
legend: {show:false},
series: [{
showMarker: false,
color: '#ED0E0E',
label: 'R spectrum',
neighborThreshold: -1
}],
axes:{
xaxis:{
label:'Restframe Wavelength'
},
yaxis:{
label:'Flux',
tickOptions:{formatString:'%.3e'}
}
},
cursor:{
show:true,
zoom:true,
tooltipLocation:'sw'
},
Canvasoverlay: {
show: false,
objects: [
{verticalLine: {
name: 'Na-ID',
x: 5893.000000,
lineWidth: 2,
color: '#F0630C',
lineCap:'butt',
yOffset:0,
shadow: true
}}
]
}
});
});
function NaID_trigger() {
var co = plot1.plugins.canvasOverlay;
var line = co.get('Na-ID');
if (line.options.show==false) line.options.show = true;
else line.options.show = false;
co.draw(plot1);
}
</script>
I then use :
<button onclick="NaID_trigger()">Na-ID</button>
to trigger the overlay on or off for instance.
PS: I tried replacing draw by replot as advised didn't work when show=false in overlays options.
I finally found the solution myself :
to not display the overlays when the jqplot loads I set the overall overlays "show" option to true.
Then within each object I set show to false.
Instead of the external to the plot function I used before I switched to an even handler of the form:
$("input[type=checkbox][name=Na-ID]").change(function(){
plot1.plugins.canvasOverlay.get('Na-ID').options.show = this.checked;
plot1.replot();
});
Now the plot display the selected overlay when checkbox is ticked and not at the beginning.
Hope this will help someone who has the same issues.

Extjs4 - Reloading store inside itemselector

I have an itemselecor inside a grid, and i have an combobox that should reload only the store inside the itemselector( the value fields should remain intact)
Here is the itemselector
var grid = Ext.widget('form', {
id: 'grid',
title: '',
width: 600,
bodyPadding: 10,
renderTo: 'itemselectorproduto',
items: [{
xtype: 'itemselector',
name: 'itemselector',
id: 'itemsel',
anchor: '100%',
imagePath: '/ux/images/',
store: store,
displayField: 'Nome',
valueField: 'ID',
value: vitrine,
allowBlank: true,
msgTarget: 'side'
}]
});
I tried to call the normal store.load(), but it have no effect and it shows no error on the console
If needed i will post more of the code, but i think just this should be enough
Thanks,
Looking through the code if ItemSelector it doesn't look like it supports any changes in the store once it's been binded. It basically creates local copies of the data. And if you call bindStore method to assign different store - it will erase your selection.
You can always improve code in ItemSelector to allow such behavior. It should not be a problem. You can subscribe to datachanged or load event of the store when binding to it, and then handle situation when store data is changed.
Actually i think the best way to do such thing is using ItemSelector`s "populateFromStore". Sure except of extending item selector. In case of extending you should look on the "onBindStore" function of the ItemSelector.
onBindStore: function(store, initial) {
var me = this;
if (me.fromField) {
me.fromField.store.removeAll()
me.toField.store.removeAll();
// Add everything to the from field as soon as the Store is loaded
if (store.getCount()) {
me.populateFromStore(store);
} else {
me.store.on('load', me.populateFromStore, me);
}
}
}
So as you see in case of the empty store it hooks to the load event. And it should be like this:
onBindStore: function(store, initial) {
var me = this;
if (me.fromField) {
me.fromField.store.removeAll()
me.toField.store.removeAll();
me.store.on('load', me.populateFromStore, me);
// Add everything to the from field as soon as the Store is loaded
if (store.getCount()) {
me.populateFromStore(store);
}
}
}