Related
I have an array of objects in state:
const [formFields, setFormFields] = useState([
{
height: 45,
label: "tv",
placeholder: "555",
name: "tv",
maxWidth: 203,
value: dataValues.tv,
priority: 1
},
{
height: 45,
label: "radio",
placeholder: "50%",
name: "radio",
maxWidth: 126,
value: dataValues.radio,
priority: 2
},
{
height: 45,
label: "instagram",
placeholder: "60%",
name: "instagram",
maxWidth: 126,
value: dataValues.instagram,
priority: 3
}
]);
I need each state value to be updated when another state updates (when I click on submit money button each state value should update), but it is not updating.
you can check the demo
any help please?
Your input elements have their value set based upon your formFields object. When you initially make the object, you use values from your dataValues object, and dataValues will automatically update based on your apiData object due to what you wrote in your useEffect hook, however you never actually wrote anything to update formFields itself.
The following code should make it work as is,
const newFormFields = [...formFields];
newFormFields[0].value = apiData.tv;
newFormFields[1].value = apiData.radio;
newFormFields[2].value = apiData.instagram;
setFormFields(newFormFields);
However I'd strongly advise refactoring. It seems like you've got a whole lot of needless redundancy here.
You mentioned in a comment that can't use indexes. In that case, something like this should work.
const newFormFields = [...formFields];
newFormFields.map(field => (field.value = apiData[field.name]));
setFormFields(newFormFields);
In the app I'm building, I have a data grid and some select boxes where the user can set filters and upon a selection it makes an AJAX call to get a new array of data from the server.
I have the grid initializing with default filters, but I can't figure out how to wipe the grid of all rows, and re-populate with a fresh array. I was trying dataView, but after reading some posts this seems to not be the answer. I find the official example-6 (ajax example) confusing.
I would like column sorting and column re-ordering to be retained when new data is loaded.
Here is the js I currently have which only initializes properly:
$(function(){
//update the grid when select values change
$('#qol_options :input').change(function(){
update_grid_data();
});
init_grid = function(){
// set grid options
var grid;
var columns = [
{id: "village", name: "Village", field: "village", sortable: true},
{id: "setting", name: "Setting", field: "setting", sortable: true},
{id: "hood", name: "N.hood", field: "hood", sortable: true},
{id: "timespan", name: "Time", field: "timespan", sortable: true},
{id: "count_0", name: "0", field: "count_0", sortable: true, width: 10},
{id: "count_1", name: "1", field: "count_1", sortable: true, width: 10},
{id: "count_2", name: "2", field: "count_2", sortable: true, width: 10},
{id: "count_3", name: "3", field: "count_3", sortable: true, width: 10},
{id: "count_4", name: "4", field: "count_4", sortable: true, width: 10},
{id: "count_6", name: "6", field: "count_6", sortable: true, width: 10},
{id: "count_7", name: "7", field: "count_7", sortable: true, width: 10},
{id: "count_8", name: "8", field: "count_8", sortable: true, width: 10},
{id: "count_total", name: "Total", field: "count_total", sortable: true},
{id: "pos_perc", name: "%", field: "pos_perc", sortable: true},
{id: "decile", name: "Decile", field: "decile", sortable: true},
];
var options = {
enableCellNavigation: true,
enableColumnReorder: true,
multiColumnSort: true
};
//get default grid data (all)
var grid_data = [{'village':0, 'setting':0, 'hood':0, 'timespan':0, 'count_0':0, 'count_1':0, 'count_2':0, 'count_3':0, 'count_4':0, 'count_6':0, 'count_7':0, 'count_8':0, 'count_total':0, 'pos_perc':0, 'decile':0}];
//create the grid instance
this_grid = new Slick.Grid("#data_table_container", grid_data, columns, options);
update_grid_data();
}
update_grid_data = function(){
var settingID = $('#settingID').val();
var villageID = $('#villageID').val();
var hoodID = $('#hoodID').val();
//init the grid
$.ajax({
type: "POST",
url: '<cfoutput>#APPLICATION.site_prefix#</cfoutput>/_global/ajax/ajax_handlers.cfm',
data: {'action': 'get_qol_report_data', 'villageID': villageID, 'settingID': settingID, 'hoodID': hoodID, 'itemID': 0, 'categoryID': 0},
dataType: 'json',
success: function(data) {
push_data_to_grid(data);
}
});
}
push_data_to_grid = function(data){
this_grid.setData(data);
this_grid.render();
}
//execute the grid init
init_grid();
});
I've faced the same problem. Please, try the below code.
function updateGridView(){
data_view.beginUpdate();
data_view.setItems(update_data);
data_view.endUpdate();
data_view.refresh();
grid.invalidate();
}
function grid_refresh(){
$.ajax("<cfoutput>#APPLICATION.site_prefix#</cfoutput>/_global/ajax/ajax_handlers.cfm",{
dataType : "json",
complete: function(xhr){
update_data = eval(xhr.responseText);
updateGridView();
}
})
}
Just call the grid_refresh() function.
I implemented something like this myself and here is how I have done it. I do use the dataview which will be wiped out every times and also the grid object which will be overwritten. I am not using your code, but instead I will show you the template which I use, I actually call the same function for loading & reloading but just make sure to empty() out the grid before you reload, see 1st line of code:
<div id="myGrid" style="width:100%;height:680px;"></div>
Then I made myself a button with an onclick event that looks something like this onclick=populateMyGrid() as a refresh button (it's actually a reload icon to make it nicer) and that event will call my function to reload the data through the $.getJSON() jQuery function, see the following code:
// Display some Market Indexes on a bar on top of the Grid
function populateMyGrid() {
// empty out the Grid before refreshing the data
$('#myGrid').empty();
// columns & options definition....
columns = [
{ id: "village", ............
];
options = {
enableCellNavigation: true,
editable: true,
............
};
ajaxURL = 'myPhpAjaxFileToPullData.php?action=getdata';
$.getJSON(ajaxURL, function (ServerResponse) {
dataView = new Slick.Data.DataView();
grid = new Slick.Grid('#myGrid', dataView, columns, options);
............
// initialize the model after all the events have been hooked up
dataView.beginUpdate();
dataView.setItems(ServerResponse.data);
dataView.endUpdate();
// Refresh the data render, if user only clicked on the refresh button instead of refreshing the whole page from browser
grid.updateRowCount();
grid.render();
}); // end of getJSON
} // end of populateMyGrid
From this code, the important part of it is to empty out the grid at first and then the last 2 rows of code for refreshing your grid with new data and make sure to re-render at last. That is the way I have it working, works like a charm...oh and I also display a text showing last refresh date+time, so it's more obvious to the user of how old the data is!
Even though it's not your code sample, you should get the idea...hope it helps :)
Also if you want to repopulate the grid with some kind of filtering you send the filtering via the ajaxURL of the $.getJSON or you could also replace it with a $.post and send it via the data property as your started, if you do it that way then move all your code into the success function (or a function call). Here is a possible solution for replacing the $.getJSON call... but please note that I did not try it but it should work:
//init the grid
$.ajax({
type: "POST",
url: '<cfoutput>#APPLICATION.site_prefix#</cfoutput>/_global/ajax/ajax_handlers.cfm',
data: {'action': 'get_qol_report_data', 'villageID': villageID, 'settingID': settingID, 'hoodID': hoodID, 'itemID': 0, 'categoryID': 0},
dataType: 'json',
success : getData
});
function getData() {
dataView = new Slick.Data.DataView();
grid = new Slick.Grid('#myGrid', dataView, columns, options);
............
// initialize the model after all the events have been hooked up
dataView.beginUpdate();
dataView.setItems(ServerResponse.data);
dataView.endUpdate();
// Refresh the data render, if user only clicked on the refresh button instead of refreshing the whole page from browser
grid.updateRowCount();
grid.render();
}
I'm looking to place a file tree (dhtmlxTree) in a form container. The container with the populated tree shows up with the correct data but is located in the wrong position in the form. I'm little confused why the container (with the tree inside) is appearing in the upper left corner of my form. This causes everything above the tree container in the form to be covered by the container. Normally any other object in the form shows up in the correct order without issue. Why is this container different?
What can I do to make the container line up with everything else?
formData = [
{type:"settings", position:"label-top"},
{type: "fieldset",name:"uploader", label: "Uploader", list:[
{type: "input", name: 'release', label: 'Release Name:',
required: "1", validate: "NotEmpty"},
{type: "container", name: "folders", label: "Select a directory:", inputWidth: 330, inputHeight: 200},
{type:"input", name:"releaseNotes", label:"Change Log Link:"},
{type:"file", name:"myFile", label:"Select an RPM",
required:"1", validate: "NotEmpty"},
{type:"button", name:"uploadbtn", value:"Upload"},
]}
];
myform = new dhtmlXForm('realUpload',formData);
folderLayout = new dhtmlXLayoutObject(myform.getContainer("folders"),"1C");
folderLayout.cells("a").hideHeader();
myTree = folderLayout.cells("a").attachTree(1);
myTree.setImagePath("../static/dhtmlx/imgs/csh_bluefolders/");
myTree.enableDragAndDrop(false);
myTree.enableIEImageFix(true);
myTree.loadXML("../static/data/evalTree.xml");
You just need to miss the layout:
myTree = new dhtmlXTreeObject(myform.getContainer("folders"),"100%", "100%", 1);
Given data in the form:
var grid_data = [ {Hello: 'World'}, {Jesus:'Navas'} ]
I wish to draw a grid like so:
The grid shows with 2 rows but with no data, I can't find the problem in the following code:
var grid_store = Ext.create('Ext.data.Store', {
fields: [
{name: 'Property'},
{name: 'Value'}
],
data: grid_data
});
// create the Grid
var grid_view = Ext.create('Ext.grid.Panel', {
store: grid_store,
renderTo: 'info_panel',
stateful: true,
stateId: 'stateGrid',
columns: [
{
text : 'Property',
width : 100,
sortable : true,
dataIndex: 'Property'
},
{
text : 'Value',
width : 80,
sortable : false,
dataIndex: 'Value'
}
],
height: 350,
width: 600,
title: 'Array Grid',
viewConfig: {
stripeRows: true
}
});
Renders to:
<div id="info_panel"></div>
If you're wondering how I got the example image, I changed the store to an ArrayStore and re-formatted the data into arrays, but I'd prefer to miss out that step and insert the data as-is.
edit:
I think what I'm really asking for is a way to alert extjs to use the JSON keys as values, as opposed to most of the grid examples out there that take the form:
{value: 'Hello'}, {property: 'World'}
As one of the commenters and your edit suggested, your grid is built to consume a json with 'Property' and 'Value' being the keys for the json objects. I don't know if it's possible for you to change the source of the data to send in the reformatted json, but if not, you can always just run a quick loop to do so after receiving the data:
var new_data = [];
Ext.each(grid_data, function(obj) {
for (var prop in obj) {
new_data.push({
Property: prop,
Value: obj[prop]
});
}
}, this);
I'm looking for a best solution how to do this.
What I have:
// model
Ext.define("User", {
extend: "Ext.data.Model",
fields: [
{name: "id", type: "int"},
{name: "name"},
{name: "description", type: "string"}
]
});
// store with data
var oStore = new Ext.data.Store({
model: "User",
data: [
{id: 1, name: {name:"John"}, description: "Fapfapfap"},
{id: 2, name: {name:"Danny"}, description: "Boobooboo"},
{id: 3, name: {name: "Tom"}, description: "Tralala"},
{id: 4, name: {name:"Jane"}, description: "Ololo"},
]
});
// and finally I have a grid panel
Ext.create("Ext.grid.Panel", {
columns: [
{dataIndex: "id", header:"ID"},
{
dataIndex: "name",
header: "Name",
renderer: function(value){return value.name;},
editor: "textfield"},
{dataIndex: "description", header: "Description", flex: 1, editor: "htmleditor"}
],
plugins: [new Ext.grid.plugin.CellEditing({clicksToEdit: 2})],
store: store,
renderTo: document.body
});
When I doublecick on a cell I see [object] Object in editor's field, and when I enter valid value than I see empty cell in the grid.
So, the question is – how could I setup celleditor to get data not from record.name but from record.name.name?
You can override get and set methods on model, so the will support multi-level field names. Below is sample implementation.
Ext.define("User", {
extend: "Ext.data.Model",
fields: [
{name: "id", type: "int"},
{name: "name"},
{name: "description", type: "string"}
],
get: function(key) {
if (Ext.isString(key) && key.indexOf('.') !== -1) {
var parts = key.split('.');
var result = this.callParent([ parts[0] ]);
return result[parts[1]];
}
return this.callParent(arguments);
},
set: function(key, value) {
if (Ext.isString(key) && key.indexOf('.') !== -1) {
var parts = key.split('.');
var result = this.get(parts[0]);
result[parts[1]] = value;
this.callParent([ parts[0], result ]);
return;
}
this.callParent(arguments);
}
});
I am not sure if store detects change made to name.name field. If no, you should also probably mark record as dirty.
Working sample: http://jsfiddle.net/lolo/dHhbR/2/
The editor accepts whatever value is provided in the "dataIndex" field of the column. Since "name" is an object, that's what you're getting. After entering a name in the editor, value is equal to a string (not an object) and your renderer is trying to get the name property of the string.
The easiest way to fix this is to make the "name" field of your store a string instead of an object. However, I'm assuming there's a reason you want to do it this way.
The CellEditing plugin has three events it can listen for: beforeedit, edit, and validateedit. You can implement a beforeedit listener to get the "name" object from the column, then get the "name" property of that object and fill the editor with that value. Then on validateedit, get the value from the editor and set the "name" property of the "name" object in the record with that value.
For quick reference, here's the event definition: CellEditing events
An easier way is to modify your User Model object to map the "name" property differently:
{name: "name", mapping:'name.name'}
then everything else stays the same.