Error when load form data in W2UI. "Cannot associate field "id" with html control" - w2ui

My form can not update data which it got from server to form's record.
Below is my w2form
$().w2form({
name: 'editSv',
method: 'GET',
style: 'border: 0px; background-color: transparent;',
recid: w2ui['grid'].records[w2ui['grid'].getSelection(true)]['id'],
url: {
get: '/api/Test/GetService/' + w2ui['grid'].records[w2ui['grid'].getSelection(true)]['id'],
save: '/api/Test/PostService'
},
formURL: '/api/Test/GetService/' + w2ui['grid'].records[w2ui['grid'].getSelection(true)]['id'],
fields: [
{ name: 'id', type: 'number', required: true },
{ name: 'servicename', type: 'text', required: true },
{ name: 'price', type: 'number', required: true },
{ name: 'unit', type: 'text' }
],
record: {
id: 0,
servicename: '',
price: 0,
unit: ''
}, onSubmit: function (formName, formObj) {
formObj.postData = formObj.postData.record;
},
onLoad: function (event) {
console.log(event.xhr);
},
actions: {
"save": function () {
var obj = this;
this.submit({}, function (data) {
if (data.status == 'success') {
w2alert(data.status);
w2ui['grid'].reload();
} else {
w2alert(data.message);
return;
}
obj.clear();
});
},
"reset": function () { this.clear(); },
}
});
This is data got from onLoad() event
{readyState: 4, responseText: "{"id":5,"servicename":"4","price":4.0000,"unit":"4"}", status: 200, statusText: "OK"}
And the message from chrome's console:
ERROR: Cannot associate field "id" with html control. Make sure html control exists with the same name.
ERROR: Cannot associate field "servicename" with html control. Make sure html control exists with the same name.
ERROR: Cannot associate field "price" with html control. Make sure html control exists with the same name.
ERROR: Cannot associate field "unit" with html control. Make sure html control exists with the same name.
I have tried to add formHTML to w2form but it makes no sense. Has anyone solved this problem?

Have you defined any HTML page for your w2ui form in this case you can use kickstart or you can define formHTML in your form:
$().w2form({
name: 'editSv',
style:'border: 0px',
focus:-1,method: 'GET',
style: 'border: 0px; background-color: transparent;',
recid: w2ui['grid'].records[w2ui['grid'].getSelection(true)]['id'],
url: {
get: '/api/Test/GetService/' + w2ui['grid'].records[w2ui['grid'].getSelection(true)]['id'],
save: '/api/Test/PostService'
},
formURL: '/api/Test/GetService/' + w2ui['grid'].records[w2ui['grid'].getSelection(true)]['id'],
formHTML:
'<div class="w2ui-page page-0">'+
' <div class="w2ui-field">'+
' <label> id </label>'+
' <div>'+
' <input name="id" type="text" />'+
' </div>'+
' </div>'+ ' <div class="w2ui-field">'+
' <label> id </label>'+
' <div>'+
' <input name="id" type="text" />'+
' </div>'+
' </div>'+ ' <div class="w2ui-field">'+
' <label> price </label>'+
' <div>'+
' <input name="price" type="text" />'+
' </div>'+
' </div>'+ ' <div class="w2ui-field">'+
' <label> unit </label>'+
' <div>'+
' <input name="unit" type="text" />'+
' </div>'+
' </div>'+
'<div class="w2ui-buttons">'+
' <button class="btn" name="Cancel">Cancel</button>'+
' <button class="btn" name="Save">Save</button>'+
'</div>',
fields: [
{ name: 'id', type: 'number', required: true },
{ name: 'servicename', type: 'text', required: true },
{ name: 'price', type: 'number', required: true },
{ name: 'unit', type: 'text' }
],
record: {
id: 0,
servicename: '',
price: 0,
unit: ''
}, onSubmit: function (formName, formObj) {
formObj.postData = formObj.postData.record;
},
onLoad: function (event) {
console.log(event.xhr);
},
actions: {
"save": function () {
var obj = this;
this.submit({}, function (data) {
if (data.status == 'success') {
w2alert(data.status);
w2ui['grid'].reload();
} else {
w2alert(data.message);
return;
}
obj.clear();
});
},
"reset": function () { this.clear(); },
}
});

Related

Clear form after submitting with vuex

I am trying to clear a form after I submit it, in this case creating a simple user. I am resetting the state with vuex (see below). But the form stays with data.
this is how the form looks like
<form #submit.prevent="onSubmit" v-if="!loading">
<div class="form-group">
<input placeholder="Name" v-model="user.name" type="text" name="name" class="form-control">
<span class="invalid-feedback" v-if="errors.name">{{ errors.name }}</span>
</div>
<div class="form-group">
<input v-bind:class="{ harError: errors.email }" placeholder="Email" v-model="user.email" type="email" name="email" class="form-control" id="validationCustom03">
<span class="invalid-feedback" v-if="errors.email">{{ errors.email }}</span>
</div>
...
the onSubmit method
/**
* on submitting the form update or crete a user
*/
onSubmit() {
let action = this.id ? 'UPDATE_USER' : 'CREATE_USER';
this.inProgress = true;
this.$store
.dispatch(action)
.then(() => {
console.log('reset or not?');
this.inProgress = false;
// navigate to user
this.$router.push('users');
})
.catch( ({ response }) => {
this.inProgress = false;
this.errors = response.data.errors;
console.log('you have an error on creating an user')
});
},
Resetting the
RESET_STATE({state}) {
console.log('reset state');
for (let f in state) {
Vue.set(state, f, initialState[f]);
}
},
the state like this
const initialState = {
users: [],
user: {
name: '',
email: '',
password: '',
type: '',
bio: '',
photo: '',
active: '1',
},
loading: false,
};
export const store = new Vuex.Store({
namespaced: true,
state: { ...initialState },
...
The input types stais with data
Ok At least I figured out myself, Insead of a const I used a function to set the initialtState like so
function initialState () {
return {
users: [],
user: {
name: '',
email: '',
password: '',
type: '',
bio: '',
photo: '',
active: '1',
},
loading: false,
}
}
export const store = new Vuex.Store({
namespaced: true,
state: { ...initialState() },
then in the mutations i assigned the intitialState to the state
mutations: {
/**
*
* #param state
* #constructor
*/
RESET_STATE: (state) => {
Object.assign(state, initialState())
},
in my user component I dispached it like so
...mapActions(['RESET_STATE']),
...
this.$store.dispatch("RESET_STATE");

Foreach instead of options binding - replicate “optionsCaption” functionality?

I have this select field:
<select data-bind="foreach: $root.feeGroups, value: $root.selectedFee">
<optgroup data-bind="attr: {label: label}, foreach: fees">
<option data-bind="text: description, option: $data"></option>
</optgroup>
</select>
The feesGroup property:
self.feeGroups([
{ label: "NEW", fees: self.fees().filter(f => f.status === "New") },
{ label: "OLD", fees: self.fees().filter(f => f.status === "Old") }
]);
And the binding handler:
ko.bindingHandlers.option = {
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
console.log(ko.toJSON(value));
ko.selectExtensions.writeValue(element, value);
}
};
My issue is with the "optionsCaption", as I am using a foreach method to generate the inner options it doesn't automatically work like it would if I was able to use the "Options" binding. But I do need to have a "Please Select..." default option.
Is there a way to do it?
You can move the foreach binding to a virtual element and add an extra option in your view that represents the null value:
<select data-bind="value: selectedFee">
<option data-bind="text: 'Select an option', option: null"></option>
<!-- ko foreach: feeGroups -->
...
<!-- /ko -->
</select>
Keep in mind that the selectedFee observable will contain null when the placeholder is active.
// From: https://stackoverflow.com/a/11190148/3297291
ko.bindingHandlers.option = {
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
ko.selectExtensions.writeValue(element, value);
}
};
const fees = [
{ type: "old", description: "test1" },
{ type: "old", description: "test2" },
{ type: "new", description: "test3" },
{ type: "new", description: "test4" }
];
const feeGroups = [
{ label: "new", fees: fees.filter(f => f.type === "new") },
{ label: "old", fees: fees.filter(f => f.type === "old") }
];
const selectedFee = ko.observable(null);
selectedFee.subscribe(console.log.bind(console, "new selection:"));
ko.applyBindings({ feeGroups, selectedFee });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="value: selectedFee">
<option data-bind="text: 'Select an option', option: null"></option>
<!-- ko foreach: feeGroups -->
<optgroup data-bind="attr: {label: label}, foreach: fees">
<option data-bind="text: description, option: $data"></option>
</optgroup>
<!-- /ko -->
</select>

Validate Input of a Form Against Another Collection

I would like to validate the input of a form against the existence of common fields in another collection. Any suggestions on how to accomplish this?
Edit: Added code example and context
I have simply built this as a prototype infrastructure.
Schemas:
Transactions.schema = new SimpleSchema({
key: { // When inserted this need to be an existing key
type: Number,
unique: true,
min: 0,
max: 1000000000,
},
employee: { // When inserted this need to be an existing employee
type: String,
regEx: /^[0-9]+[NCV]$/,
min: 4,
max: 128,
},
});
Keys.schema = new SimpleSchema({
code: {
type: Number,
unique: true,
min: 0,
max: 1000000000,
},
name: {
type: String,
min: 3,
max: 128,
},
});
Employees.schema = new SimpleSchema({
empId: {
type: String,
regEx: /^[0-9]+[NCV]$/,
min: 4,
max: 128,
},
});
Currently, I'm simply using a validation and upsert method for ease of troubleshooting and experimenting.
export const upsertTransaction = new ValidatedMethod({
name: 'transactions.upsert',
validate: new SimpleSchema({
_id: { type: String, optional: true },
key: { type: Number, optional: true }, // I think this is where I need to validate existing key
employee: { type: String, optional: true }, // I think this is where I need to validate existing employee
}).validator(),
run(document) {
return Transactions.upsert({ _id: document._id }, { $set: document });
},
});
React form:
export default class TransactionEditor extends React.Component {
componentDidMount() {
transactionEditor({ component: this });
setTimeout(() => { document.querySelector('[name="key"]').focus(); }, 0);
}
render() {
const { trans } = this.props;
return (<form
ref={ form => (this.transactionEditorForm = form) }
onSubmit={ event => event.preventDefault() }
>
<FormGroup>
<ControlLabel>Key</ControlLabel>
<FormControl
type="number"
name="key"
defaultValue={ trans && trans.key }
placeholder="1234"
/>
</FormGroup>
<FormGroup>
<ControlLabel>Employee</ControlLabel>
<FormControl
type="text"
name="employee"
defaultValue={ trans && trans.employee }
placeholder="12345V"
/>
</FormGroup>
<Button type="submit" bsStyle="success">
{ trans && trans._id ? 'Save Changes' : 'Add Transaction' }
</Button>
</form>);
}
}
I'm using https://github.com/themeteorchef/base as a framework, for reference.

how to enable swipe carousel event for extjs5

Ext.define('SApp.view.appCrd.InCarousel', {
extend: 'Ext.view.View',
xtype: 'InCarousel',
id:'InCarouselContent',
requires: ['Ext.data.Store',
'SApp.model.appCrd.InDetailModel',
'SApp.model.appCrd.InMeasureModel',
],
tpl: [
'<tpl for=".">',
'<div class="item thumb-wrap">',
'<div class="thumb" style="width:180px; height:180px;">',
'<div ><span class="thumb-title-home-page {class}"><span>{InName}</span></span></div>',
'<tpl for="measureData">',
'<div class="thumb-description" ><span class="thumb-description-name">{key}</span> <span class="thumb-description-value">{value}</span></div>',
'</tpl>',
'</div>',
'</div>',
'</tpl>'
],
itemSelector: 'div.thumb-wrap',
multiSelect: true,
listeners: {
click: {
element: 'el',
fn: function(){var createappCrdInDetailView = new Ext.create('SApp.view.appCrd.appCrdInDetailView');
var vport = Ext.getCmp('appCrdMainContent');
vport.removeAll(true, true);
vport.add(createappCrdInDetailView.show());}
},
dblclick: {
element: 'body',
fn: function(){ console.log('dblclick body'); }
}
},
singleSelect: true,
cls: 'x-image-view',
initComponent: function() {
this.store = Ext.create('Ext.data.Store', {
storeId: 'CustomerDataStore',
autoLoad: true,
model: 'SApp.model.appCrd.InDetailModel',
proxy: {
type: 'ajax',
url : '../SApp/resources/data/appCrd/InList.json',
reader: {
type: 'json'
}
}
});
this.callParent();
}
});
code is working after changing listener
swipe: {
element: 'el', //bind to the underlying body property on the panel
event: 'swipe',
fn: function(event){
if(event.direction == 'left'){
slideRight()
}else{
slideLeft()
}
}
}

react.js - show a message on and after form submission

On submitting the form, I want to show 'Please wait ..' and on successful submission the data returned from server. Using jQuery , it is easy to do. But there should be a React way as React does not like such kind of direct DOM manipulation - I think . 1) Am I right ? 2) How to show the message on (not after ) form submission?
var FormComp = React.createClass({
handleSubmit:function(){
var userName=this.refs.userName.getDOMNode().value.trim();
var userEmail= this.refs.userEmail.getDOMNode().value.trim();
if(!userName || !userEmail){
return;
}
this.props.onFormSubmit({userName:userName, userEmail:userEmail,url:"/api/submit"});
this.refs.userName.getDOMNode().value='';
this.refs.userEmail.getDOMNode().value='';
return;
},
render: function() {
var result=this.props.data;
return (
<div className={result}>{result.message}</div>
<form className="formElem" onSubmit={this.handleSubmit}>
Name: <input type="text" className="userName" name="userName" ref="userName" /><br/>
Email: <input type="text" className="userEmail" name="userEmail" ref="userEmail" /><br/>
<input type="submit" value="Submit" />
<form >
</div>
);
}
});
var RC= React.createClass({
getInitialState: function() {
return {data: ""};
},
onFormSubmit:function(data){
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: data,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
render:function(){
return <FormComp onFormSubmit={this.onFormSubmit} data={this.state.data}/>
}
});
React.render(
<RC/>,
document.getElementById('content')
);
This is definitely something React can handle, no direct DOM manipulation is needed. You're almost there, just need to reorganize a little. Here's one way to approach this (with comments around important changes):
var FormComp = React.createClass({
// To get rid of those input refs I'm moving those values
// and the form message into the state
getInitialState: function() {
return {
name: '',
email: '',
message: ''
};
},
handleSubmit: function(e) {
e.preventDefault();
var userName = this.state.name.trim();
var userEmail = this.state.email.trim();
if(!userName || !userEmail) return;
this.setState({
name: '',
email: '',
message: 'Please wait...'
});
// I'm adding a callback to the form submit handler, so you can
// keep all the state changes in the component.
this.props.onFormSubmit({
userName: userName,
userEmail: userEmail,
url: "/api/submit"
}, function(data) {
this.setState({ message: data });
});
},
changeName: function(e) {
this.setState({
name: e.target.value
});
},
changeEmail: function(e) {
this.setState({
email: e.target.value
});
},
render: function() {
// the message and the input values are all component state now
return (
<div>
<div className="result">{ this.state.message }</div>
<form className="formElem" onSubmit={ this.handleSubmit }>
Name: <input type="text" className="userName" name="userName" value={ this.state.name } onChange={ this.changeName } /><br />
Email: <input type="text" className="userEmail" name="userEmail" value={ this.state.email } onChange={ this.changeEmail } /><br />
<input type="submit" value="Submit" />
</form>
</div>
);
}
});
var RC = React.createClass({
onFormSubmit: function(data, callback){
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: data,
success: callback,
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
render: function() {
return <FormComp onFormSubmit={this.onFormSubmit} />
}
});
React.render(
<RC />,
document.getElementById('content')
);