ExtJS 3: form load with several items with identical names - javascript

I have an ExtJS form which contains several items that have the same name. I expect that when the form is loaded with the values from server-side all of those equally named components will get assigned the same relevant value.
Apparently, what happens is that only the first element from the group of equally named gets the value, others are skipped.
Is there an easy way to alter this observed behavior?
UPDATE
Below is the code of the form:
var productionRunAdvancedParametersForm = new Ext.form.FormPanel({
region : 'center',
name : 'productionRunAdvancedParametersCommand',
border : false,
autoScroll : true,
buttonAlign : 'left',
defaults : {
msgTarget : 'side'
},
layoutConfig : {
trackLabels : true
},
labelWidth : 200,
items : [
{
xtype : 'fieldset',
title : 'ASE',
collapsible : true,
autoHeight : true,
items : [ {
xtype : 'hidden',
name : 'genScens'
}, {
xtype : 'checkbox',
name : 'genScens',
fieldLabel : 'GEN_SCENS',
disabled : true
}]
}]
,
listeners : {
beforerender : function(formPanel) {
formPanel.getForm().load({
url : BASE_URL + 'get-data-from-server.json',
method : 'GET',
success : function(form, action) {
var responseData = Ext.util.JSON.decode(action.response.responseText);
if (!responseData.success) {
Screen.errorMessage('Error', responseData.errorMessage);
}
},
failure : function(form, action) {
Ext.Msg.alert("Error", Ext.util.JSON.decode(action.response.responseText).errorMessage);
}
});
}
}
});
The server response is:
{"data":{"genScens":true},"success":true}
What happens is only the hidden component gets value 'true', the disabled checkbox doesn't get checked. If I swap them in the items arrays, then the checkbox is checked but the hidden doesn't get any value.

The behaviour you see is exactly what I'd expect.
Inside a form, using the same field name multiple times -unless you use it for radiobuttons, which is not the case- is an error. Just think about what the form submit function should do in this case: should it send the same key (input name) twice, possibly with different values?
(Obviously, in the case of radiobuttons the answer is simple: sent the input name as key, and the checked radiobutton's value as value).
What Ext does here is, scan the form seaching for the input field matching the name, and then assign the value to the first matching input (since it assumes no duplicate names).
You can work it around simply by:
using two different names in the form (eg. genScens and genScens_chk )
sending the same value under two different keys in the server-side response, e.g.
{"data":{"genScens":true,"genScens_chk":true},"success":true}
Please note: if you cannot alter the server response, still use two different names, just add a callback to the success function, setting the genScens_chk value accordingly, like that:
success : function(form, action) {
var responseData = Ext.util.JSON.decode(action.response.responseText);
if (!responseData.success) {
Screen.errorMessage('Error', responseData.errorMessage);
}
else{
formPanel.getForm().findField("genScens_chk").
setValue(responseData.data.genScens);
}
},

Related

How to pass/delete array params in HTTP Params with Angular

I have an Array of statuses objects. Every status has a name, and a boolean set at false by default.
It represent checkbox in a form with filters, when a checkbox is checked bool is set at true :
const filters.statuses = [
{
name: "pending",
value: false
},
{
name: "done",
value: false
},
];
I am using Angular HTTP Params to pass params at the URL.
filters.statuses.forEach((status) => {
if (status.value) {
this.urlParams = this.urlParams.append('statuses[]', status.name);
}
});
Url params looks like when a status is checked :
&statuses%5B%5D=pending
My problem is when I want to unchecked.
I know HTTP Params is Immutable, so, I'm trying to delete the param when checkbox is unchecked, so set to false :
...else {
this.urlParams = this.urlParams.delete('statuses');
}
But, it not works, URL doesn't change.
And if I re-check to true after that, the URL looks like :
&statuses%5B%5D=pending&statuses%5B%5D=pending
How can I delete params, if the status value is false, and keep others statuses in URL ?
Project on Angular 10.
Thanks for the help.
UPDATE : It works to delete, my param name was not good :
else {
this.urlParams = this.urlParams.delete('statuses[]', status.name);
}
But, my other problem, it's when I check 2 or more checkbox, the append function write on URL : &statuses%5B%5D=pending&statuses%5B%5D=pending&statuses%5B%5D=done
I have prepared an example to try to answer your question (If I understand this right way).
You can change the checkboxes state or the URL to play with it. Also, I added helper buttons, which will navigate you to different cases (by changing the URL).
Here is the example: https://stackblitz.com/edit/angular-router-basic-example-cffkwu?file=app/views/home/home.component.ts
There are some parts. We will talk about HomeComponent.
You have ngFor which displays statuses, I handled state using ngModel (you can choose whatever you want).
You have a subscription to the activatedRoute.queryParams observable, this is how you get params and set up checkboxes (the model of the checkboxes)
You have the ngModelChange handler, this is how you change the route according to the checkboxes state
Let's focus on 2 & 3 items.
The second one. Rendering the correct state according to the route query params. Here is the code:
ngOnInit() {
this.sub = this.activatedRoute.queryParams.subscribe((params) => {
const statusesFromParams = params?.statuses || [];
this.statuses = this.statuses.map((status) => {
if (statusesFromParams.includes(status.name)) {
return {
name: status.name,
active: true,
};
}
return {
name: status.name,
active: false,
};
});
});
}
Here I parse the statuses queryParam and I set up the statuses model. I decide which is active and which is not here.
The third one. You need to update the URL according to the checkboxes state. Here is the code:
// HTML
<ng-container *ngFor="let status of statuses">
{{ status.name}} <input type="checkbox" [(ngModel)]="status.active" (ngModelChange)="onInputChange()" /> <br />
</ng-container>
// TypeScript
onInputChange() {
this.router.navigate(['./'], {
relativeTo: this.activatedRoute,
queryParams: {
statuses: this.statuses
.filter((status) => status.active)
.map((status) => status.name),
},
});
}
Here you have the ngModelChange handler. When any checkbox is checked/unchecked this handler is invoked. In the handler, I use the navigate method of the Router to change the URL. I collect actual checkboxes state and build the query parameters for the navigation event.
So, now you have a binding of the checkboxes state to the URL and vice versa. Hope this helps.

enable/disable 'add new' button in jquery jtable

I am using jquery jtable to display tables from mysql db. In one of the tables, I want user to be allowed to insert only one row. i.e. disable add new record button once first row is inserted.
Is it possible to do this?
I have following structure defined for jtable:
$('#SchoolTableContainer').jtable({
title : 'Schools List',
paging: true, //Enable paging
pageSize: 10, //Set page size (default: 10)
sorting: true, //Enable sorting
defaultSorting: 'name ASC', //Set default sorting
actions : {
listAction : 'ControllerAdminSchool?action=list',
createAction : 'ControllerAdminSchool?action=create',
updateAction : 'ControllerAdminSchool?action=update',
deleteAction : 'ControllerAdminSchool?action=delete'
},
fields : {
id : {
title : 'School Id',
key : true,
list : false
},
name : {
title : 'Name'
},
address : {
title : 'Address'
},
email : {
title : 'Email'
},
phone : {
title : 'Phone'
},
website : {
title : 'Website'
},
remark : {
title : 'remark'
}
}
});
$('#SchoolTableContainer').jtable('load');
Similarly can enable/disable edit & delete buttons individually for each row depending upon some condition (e.g. if name has some particular value say admin then disable delete)?
Also how to add custom button in each row (e.g. to view details I can click on a view button and can view full details of corresponding row)?
To dynamically disable the "add new record" functionality you can remove the button by defining a function handling the recordsLoaded event:
recordsLoaded: function(event, data) {
var rowCount = data.records.length;
if (rowCount>=1){
$('#tableContainer').find('.jtable-toolbar-item.jtable-toolbar-item-add-record').remove();
}
}
similarly, to keep the behavior of your table coherent you should implement the same kind of logic for the events rowInserted and rowsRemoved.
I'm aware that it's a DOM fiddling rather than controlling the behavior of jtable to stop offering the action, however hikalkan's (jtable's author) answer here leads me to believe it's the preferred approach.
For the custom buttons on each row i normally implement the first solution described here.

cellEditableCondition always returning false

I'm trying to get a grid on a website to allow the user the ability to edit cell values for only certain properties. I'm sorry if this is basic level, but I'm new to this type of advanced website design.
I've been looking around and found two previous questions that I tried to draw my functionality from:
How to find if an array contains a specific string in JavaScript/jQuery?
nggrid how can I disable/enable individual column
Combining these, I created the following code so that any row that has "Value" equal to anything in my noneditable list will not be open for the user to change:
noneditable = [ "hamburger", "fries" ]
$scope.gridOptions = {
data : 'gridData',
enableRowSelection : false,
enableCellEditOnFocus : true,
showFooter : true,
columnDefs : [ {
field : 'name',
displayName : 'Parameter',
enableCellEdit : false
}, {
field : 'value',
displayName : 'Value',
/**enableCellEdit : true**/
cellEditableCondition : '$.inArray(row.getProperty(\'value\'), noneditable) == -1'
} ]
};
I'm running this, and its compiling, but all cells in column "Value" are noneditable, even the ones contained in the list (tried both > -1 and == -1 to see if I had just gotten the logic wrong, but both produce the same results). Any thoughts? And thank you in advance.
UPDATE (3/27/15):
I was unable to find the solution to this problem, instead I worked around it by just adding another property on the list of values to be displayed. My operational code is:
$scope.gridOptions = {
data : 'gridData',
enableRowSelection : false,
enableCellEditOnFocus : true,
showFooter : true,
columnDefs : [ {
field : 'name',
displayName : 'Parameter',
enableCellEdit : false
}, {
field : 'value',
displayName : 'Value',
cellEditableCondition : 'row.getProperty(\'editable\')'
}]
};
I'm just posting this code in case it helps someone else out.

ExtJS 4, customize boolean column value of Ext.grid.Panel

Good day, i have a grid with boolean column:
var grid = Ext.create('Ext.grid.Panel', {
...
columns: [{
dataIndex: 'visibleForUser',
text: 'Visible',
editor: {
xtype: 'checkboxfield',
inputValue: 1 // <-- this option has no effect
}
},
...
Grid's store is remote via JSON proxy. When i save or update row, the resulting JSON
look like:
{... visibleForUser: false, ... }
As you see, ExtJS serializes checkbox value as true or false JSON terms.
I need to customize this and serialize to, say, 1 and 0, any suggestion how to accomplish this ? Thank you.
I've just changed my checkboxes system-wide to always act/respond to 0 and 1:
Ext.onReady(function(){
// Set the values of checkboxes to 1 (true) or 0 (false),
// so they work with json and SQL's BOOL field type
Ext.override(Ext.form.field.Checkbox, {
inputValue: '1',
uncheckedValue: '0'
});
});
But you can just add this configs per checkbox.
Ext JS 4.1.1 has a new serialize config on record fields. When a writer is preparing the record data, the serialize method is called to produce the output value instead of just taking the actual field value. So you could do something like this:
fields: [{
name: "visibleForUser",
type: "boolean",
serialize: function(v){
return v ? 1 : 0;
}
/* other fields */
}]
I try to avoid overriding default component behavior whenever possible. As I mentioned, this only works in 4.1.1 (it was introduced in 4.1.0 but I believe it was broken). So if you're using an earlier version, one of the other answers would suit you better.
You can try to override getValue
Ext.define('Ext.form.field.Checkbox', {
override : 'Ext.form.field.Checkbox',
getValue: function () {
return this.checked ? 1 : 0;
}
});

Extjs 4 gridrow draws blank after model save

I have a couple of grids, divided in an accordion layout. They basicly show the same kind of data so an grouped grid should do the trick, however it looks really good this way and so far it works good too.
Left of the grids there is a form panel which is used to edit grid records, when I click on a record in the grid the appropriate data shows up in the form. I can edit the data, but when I click the save button, which triggers an 'model'.save() action, the related grid row draws blank and a dirty flag appears. I checked the model and the 'data' attribute doesn't contain any data but the id, the data is present in the 'modified' attribute.
I read that the red dirty flag means that the data isn't persisted in the back-end, but in this case it is. The request returns with a 200 status code and success : true.
The onSave method from the controller:
onSave : function() {
// Get reference to the form
var stepForm = this.getStepForm();
this.activeRecord.set( stepForm.getForm().getValues() );
this.activeRecord.save();
console.log( this.activeRecord );
}
The step store:
Ext.define( 'Bedrijfsplan.store.Steps', {
extend : 'Ext.data.Store',
require : 'Bedrijfsplan.model.Step',
model : 'Bedrijfsplan.model.Step',
autoSync : true,
proxy : {
type : 'rest',
url : 'steps',
reader : {
type : 'json',
root : 'steps'
},
writer : {
type : 'json',
writeAllFields : false,
root : 'steps'
}
}
} );
Step model:
Ext.define( 'Bedrijfsplan.model.Step', {
extend : 'Ext.data.Model',
fields : [ 'id', 'section_id', 'title', 'information', 'content', 'feedback' ],
proxy : {
type : 'rest',
url : 'steps',
successProperty : 'success'
}
} );
Step grid
Ext.define( 'Bedrijfsplan.view.step.Grid', {
extend : 'Ext.grid.Panel',
alias : 'widget.stepsgrid',
hideHeaders : true,
border : false,
columns : [ {
header : 'Titel',
dataIndex : 'title',
flex : 1
} ]
} );
I spend a couple of hours searching and trying, but I still haven't found the solution. Some help on this matter would be appreciated :)
Your model updating code:
this.activeRecord.set( stepForm.getForm().getValues() );
Should work, but I might try splitting it into two lines and setting a breakpoint to verify that getValues() is returning what you're expecting.
Also ensure that you have the name attribute set for each field in your form and that it matches exactly to the names of fields in your model.
Finally, it's better to call .sync() on the store rather than .save() on the model when you're working with a model that belongs to a store. They option autoSync: true on the store will make this happen automatically each time you make a valid update to one of its models.
The BasicForm.loadRecord and BasicForm.updateRecord methods provide a nice wrapper around the functionality you're seeking that may work better:
onRowSelected: function(activeRecord) {
stepForm.getForm().loadRecord(activeRecord);
}
onSaveClick: function() {
var activeRecord = stepForm.getForm().getRecord();
stepForm.getForm().updateRecord(activeRecord);
activeRecord.store.sync();
}
The only oddity I see is with your: this.activeRecord.set( stepForm.getForm().getValues() );
I've always used .set() on the store never on the record. e.g.:
myDataStore.set( stepForm.getForm().getValues() );

Categories

Resources