I want to save the user selected and predefined fields of an AlloyUI FormBuilder. I have tried to use JSON.stringify(formBuilder.get('fields')), but I get the following error:
Uncaught TypeError: Converting circular structure to JSON
How can I save (and restore) the fields of an AlloyUI FormBuilder?
In order to save the fields of an AlloyUI FormBuilder, you can use field.getAttributesForCloning() to obtain the important field attributes. Then you can combine those attributes into an array. Finally, you can convert the array to JSON to save it with JSON.stringify():
var fields = [];
formBuilder.get('fields').each(function(field) {
fields.push(field.getAttributesForCloning());
});
fields = JSON.stringify(fields);
If you want to restore the fields, you can use JSON.parse() on the JSON:
new Y.FormBuilder({
/* ...your code here... */
fields: JSON.parse(fields)
}).render();
Here's a runnable example using AlloyUI's example FormBuilder code:
YUI().use('aui-form-builder', function(Y) {
var formBuilder = new Y.FormBuilder({
availableFields: [{
iconClass: 'form-builder-field-icon-text',
id: 'uniqueTextField',
label: 'Text',
readOnlyAttributes: ['name'],
type: 'text',
unique: true,
width: 75
}, {
hiddenAttributes: ['tip'],
iconClass: 'form-builder-field-icon-textarea',
label: 'Textarea',
type: 'textarea'
}, {
iconClass: 'form-builder-field-icon-checkbox',
label: 'Checkbox',
type: 'checkbox'
}, {
iconClass: 'form-builder-field-icon-button',
label: 'Button',
type: 'button'
}, {
iconClass: 'form-builder-field-icon-select',
label: 'Select',
type: 'select'
}, {
iconClass: 'form-builder-field-icon-radio',
label: 'Radio Buttons',
type: 'radio'
}, {
iconClass: 'form-builder-field-icon-fileupload',
label: 'File Upload',
type: 'fileupload'
}, {
iconClass: 'form-builder-field-icon-fieldset',
label: 'Fieldset',
type: 'fieldset'
}],
boundingBox: '#myFormBuilder',
fields: [{
label: 'City',
options: [{
label: 'Ney York',
value: 'new york'
}, {
label: 'Chicago',
value: 'chicago'
}],
predefinedValue: 'chicago',
type: 'select'
}, {
label: 'Colors',
options: [{
label: 'Red',
value: 'red'
}, {
label: 'Green',
value: 'green'
}, {
label: 'Blue',
value: 'blue'
}],
type: 'radio'
}]
}).render();
Y.one('#resetFormBuilder').on('click', function(event) {
var fields = [];
formBuilder.get('fields').each(function(field) {
fields.push(field.getAttributesForCloning());
});
fields = JSON.stringify(fields);
formBuilder.destroy();
event.target.set('style', 'display: none;');
new Y.FormBuilder({
/* ...your code here... */
boundingBox: '#myFormBuilder',
fields: JSON.parse(fields)
}).render();
});
});
<script src="http://cdn.alloyui.com/3.0.1/aui/aui-min.js"></script>
<link href="http://cdn.alloyui.com/3.0.1/aui-css/css/bootstrap.min.css" rel="stylesheet"></link>
<div class="yui3-skin-sam">
<button id="resetFormBuilder" class="btn btn-primary">
Reset <code>FormBuilder</code>
</button>
<div id="wrapper">
<div id="myFormBuilder"></div>
</div>
</div>
Related
I would like to show and hide table column dynamically with checkbox and save it the option to localstore in vue 2. I find a jquery version but when I tried to use it did not worked.
I am a beginer in vue.
Thank you for your help.
My vue table:
export default {
extends: axiosGetPost,
props: ['id','tab_name', 'route_name'],
data() {
return {
hidePreLoader: true,
price: '',
purchase_price: '',
selling_price: '',
products: {},
tableOptions: {
tableName: 'products',
columnSelect : true,
columns: [
{
title: 'lang.item_image',
key: 'image',
type: 'images',
source: '/uploads/products',
imagefield: 'imageURL',
sortable: false
},
{title: 'lang.sku', key: 'sku', type: 'text', sortable: true},
{title: 'lang.sku_2', key: 'sku_2', type: 'text', sortable: true},
{title: 'lang.sku_3', key: 'sku_3', type: 'text', sortable: true},
{title: 'lang.sku_4', key: 'sku_4', type: 'text', sortable: true},
{title: 'lang.attribute_values', key: 'attribute_values', type: 'text', sortable: true},
{title: 'lang.quantity', key: 'test', type: 'text', sortable: true},
{title: 'lang.selling_price', key: 'selling_price', type: 'text', sortable: true},
{title: 'lang.receiving_price', key: 'purchase_price', type: 'text', sortable: true},
],
formatting : ['selling_price','purchase_price'],
source: '/products/variantDetails/' + this.id,
},
}
},
I run out of ideas.
Thank you for your help.
For this you need to set defaults so that the checkbox values first try to read from localStorage. Then create a method when the input is clicked to change the value and update the value set into storage.
Vue.use(VueTables.ClientTable);
new Vue({
el: "#app",
data: {
columns: ['name', 'code'],
columnHidden: {
name: localStorage.getItem('name') || false,
code: localStorage.getItem('code') || false
},
data: getData()
},
methods: {
toggleColumn(column) {
this.columnHidden[column] = !this.columnHidden[column];
localStorage.setItem(column, true);
}
}
});
function getData() {
return [{
code: "ZW",
name: "Zimbabwe"
}, {
code: "ZM",
name: "Zambia"
}, {
code: "YE",
name: "Yemen"
}];
}
<div id="app" v-cloak>
<template v-for="column in columns">
<label for=`toggleTable${column}`>{{`Toggle ${column}`}}</label>
<input v-on:click="toggleColumn(column)" id=`toggleTable${column}` type="checkbox" :checked="columnHidden[column]" />
<br />
</template>
<v-client-table :columns="columns" v-model="data">
</v-client-table>
</div>
I have this json data:
{
id: 1,
name: 'something',
description: 'somethingsomething',
customers: [{
id: 1,
username: 'cust1'
}, {
id: 2,
username: 'cust2'
}]
}
While I have no problems displaying the first three fields on the gridpanel, I however have an issue retrieving the array object for the customers field. My model goes like this:
fields: [
'id', {
name: 'name',
sortType: Ext.data.SortTypes.asUCString
},
'permanent', {
name: 'description',
Type: Ext.data.SortTypes.asUCString
}, {
name: 'customers',
Type: Ext.data.SortTypes.asUCString
}, {
name: 'username',
Type: Ext.data.SortTypes.asUCString,
mapping: 'customers[0].username'
}
]
When I try to access customers[0].username, it only retrieves the ones on that specified index. Removing the index number returns undefined as I assume it is looking for what index to return from. How do I properly retrieve all of customers: [] and display it to my grid where it is structured as:
{
xtype: 'gridpanel',
store: oStore,
viewConfig: {
loadMask: false,
enableTextSelection: true
},
hideHeaders: false,
bodyBorder: true,
columns: [{
text: 'Customer',
dataIndex: 'username',
flex: 1
}, {
header: '',
xtype: 'actioncolumn',
itemId: 'remove-player-btn',
width: 50,
sortable: false,
resizable: false,
menuDisabled: true,
items: [{
icon: 'resources/img/x.png',
tooltip: 'Remove Player',
scope: oMe
}],
editor: {
xtype: 'text',
name: 'deleteRow'
}
}]
}
You can use convert function available in model.This convert function is used for some calculation purpose & map response data for our needs.For example I will map username as below:
fields: [
{
name:'username',
convert:function(value,model)
{
return model.data.customers.username;
}
}
]
Use same technique for id field.Reply if any issues.
I am working on small example to understand association which is working fine in Ext js 5 but failing in Ext js 6 version.
Ext.onReady(function() {
// parent model
Ext.define('Continent', {
extend: 'Ext.data.Model',
field: ['name'],
hasMany: {
model: 'Country',
name: 'countries'
}
});
//child model
Ext.define('Country', {
extend: 'Ext.data.Model',
field: ['name'],
associations: [{
type: 'belongsTo',
model: 'Continent',
associationKey: 'countries',
}]
});
//created store for parent which contains child data
Ext.define('ContinentStore', {
extend: 'Ext.data.Store',
storeId: 'continent',
model: 'Continent',
autoLoad: true,
proxy: {
type: 'memory',
data: [{
name: 'Asia',
countries: [{
name: 'India'
}, {
name: 'Srilanka'
}, {
name: 'Bangladesh'
}]
}, {
name: 'Africa',
countries: [{
name: 'Nigeria'
}, {
name: 'Kenya'
}, {
name: 'South Africa'
}]
}, {
name: 'America',
countries: [{
name: 'West'
}, {
name: 'East'
}, {
name: 'South'
}]
}]
}
});
var continentGrid = Ext.create('Ext.grid.Panel', {
title: 'Continent Grid',
store: Ext.create('ContinentStore'),
width: '50%',
height: '100%',
listeners: {
select: function(cmp, record, index) {
//record.countries() will return new store.
// to append new store I have used reconfigure method.
Ext.getCmp('CountryGrid').reconfigure(record.countries());;
}
},
columns: [{
dataIndex: 'name',
text: 'Continent',
flex: 1
}]
});
var countryGrid = Ext.create('Ext.grid.Panel', {
title: 'Country Grid',
id: 'CountryGrid',
width: '50%',
height: '100%',
columns: [{
dataIndex: 'name',
text: 'Country',
flex: 1
}]
});
Ext.create('Ext.window.Window', {
width: 500,
height: 400,
layout: 'hbox',
autoShow: true,
items: [continentGrid, countryGrid]
})
//console.log(continent);
});
when I try to run the example in Ext js 6 verison getting below error.
Uncaught Error: hasMany ("Continent") and belongsTo ("Country") should not be used in conjunction to declare a relatextionship. Use only one.(…)
working fiddle
I have a listContainer and on tap of any item in the list, I open another page known as editContainer with the record from list. In the edit page, I want to disable a dropdown based on the value of another field, is there any way I can get the values in record in the initialize function of editContainer? Here is my code:-
onListItemTap:function(dataview,index,target,record,e,eOpts)
{
if(record)
this.editContainer = Ext.create('myApp.view.EditContainer',{title:'Edit Data'});
this.editContainer.setRecord(record);
this.getMainNav().push(this.editContainer);
}
Above code opens editContainer when a list item is selected. Below is my EditContainer
Ext.define('myApp.view.EditContainer', {
extend: 'Ext.Container',
requires: [
'Ext.form.Panel',
'Ext.form.FieldSet',
'Ext.field.Select'
],
config: {
id: 'editContainer',
autoDestroy: false,
layout: 'fit',
items: [
{
xtype: 'formpanel',
id: 'editFormPanel',
padding: 10,
styleHtmlContent: true,
autoDestroy: false,
layout: 'fit',
items: [
{
xtype: 'fieldset',
id: 'nameFieldSet',
autoDestroy: false,
items: [
{
xtype: 'textfield',
id: 'siteName',
itemId: 'mytextfield',
label: 'Name',
labelWidth: '35%',
name: 'name'
},
{
xtype: 'selectfield',
id: 'role',
itemId: 'myselectfield4',
label: 'Role',
labelWidth: '35%',
name: 'role',
options: [
{
text: 'Unassigned',
value: 'Unassigned'
},
{
text: 'Role1',
value: 'role1'
}
]
},
{
xtype: 'selectfield',
id: 'type',
label: 'Type',
labelWidth: '35%',
name: 'type',
options: [
{
text: 'Default',
value: 'Default'
},
{
text: 'Custom',
value: 'custom'
}
]
},
{
xtype: 'selectfield',
id: 'roleValue',
label: 'Role Value',
labelWidth: '35%',
name: 'rolevalue',
options: [
{
text: 'value1',
value: 'value1'
},
{
text: 'value2',
value: 'value2'
},
{
text: 'value3',
value: 'value3'
}
]
}
]
}
]
}
],
listeners: [
{
fn: 'onTextfieldKeyup',
event: 'keyup',
delegate: 'textfield'
},
{
fn: 'onSelectfieldChange',
event: 'change',
delegate: 'selectfield'
}
]
},
onTextfieldKeyup: function(textfield, e, eOpts) {
this.fireEvent('change', this);
},
onSelectfieldChange: function(selectfield, newValue, oldValue, eOpts) {
this.fireEvent('change', this);
},
initialize: function() {
this.callParent();
var record;
//Code to disable roleValue selectfield if Role is unassigned.
},
updateRecord: function(newRecord) {
var me = this,
myPanel = me.down('#editFormPanel');
if(myPanel)
myPanel.setRecord(newRecord);
},
saveRecord: function() {
var me =this,
myStore = Ext.data.StoreManager.lookup('MyStore');
var formPanel = me.down('#editFormPanel'),
record = formPanel.getRecord();
formPanel.updateRecord(record);
return record;
}
});
Since creating your editContainer and setting its data are two different steps in your code you can't use the initialize method of the editContainer.
But you can override the setRecord method of the editContainer, so it additionally disables the dropdown.
Since you push the editContainer onto a navigation view you could also use the activate event of the editContainer to disable the dropdown.
Maybe you can create a quick store on the fly, as a place to have a reference to that data...
//in your controller where you set the record
var mod = Ext.define('app.model.PanelDataModel', {
extend: 'Ext.data.Model',
config: {
fields: [
'roleValue'
]
}
});
var sto = Ext.create('Ext.data.Store', {
model: mod,
id:'PanelDataStore'
});
sto.add({
roleValue: record.roleValue
});
sto.sync();
//Now in your panel's initialize method:
var pstore = Ext.getStore('PanelDataStore');
pstore.load();
if(pstore.data.all[0].data.roleValue == 'unassigned'){
Ext.getCmp('roleValue').setDisabled(true);
}
So I have a form and its respective store. The store works fine and it keeps the data in localStorage, but when I open the app again and try to update the form with the data from localStorage it doesn't work!
Any help would be much appreciated!
...
var optionsModel = new Ext.regModel('Options',{
fields: [ {name:'id', type:'int'}, 'language', 'range', 'limit', 'filters'],
proxy: { type: 'localstorage', id: 'options' }
});
...
Options = new Ext.Panel({
id: 'options',
floating: true,
hidden: true,
scroll: 'vertical',
hideOnMaskTap: false,
width:'50%',
autoHeight:true,
style:'min-width:300px;',
items: [{
title: 'Options',
xtype: 'form',
id: 'optionsForm',
items: [{
xtype: 'hiddenfield',
name: 'id',
value: 1
},{
xtype: 'fieldset',
title: 'Language',
defaults: {
labelWidth: '65%'
},
items: [{
xtype: 'selectfield',
name: 'language',
value: 'EN',
labelWidth: 0,
options: [{
text: 'English',
value: 'EN',
selected:true
}, {
text: 'Português',
value: 'PT'
}]
}]
},{
xtype: 'fieldset',
title: 'Limits',
defaults: {
// labelAlign: 'right'
labelWidth: '40%',
xtype: 'sliderfield',
},
items: [{
name: 'range',
label: 'Range',
value:1,
increment:1,
minValue: 1,
maxValue: 10
},{
name: 'limit',
label: 'Limit',
value:25,
increment:5,
minValue: 10,
maxValue: 50
}]
}],
store: new Ext.data.Store({
storeId: 'OptionsStore',
model: 'Options',
}),
/**
* Add custom event listener
*/
addEventListener: function(){
Options.on('beforeshow',this.loadSettings,this);
Options.on('beforehide',this.saveAction,this);
},
/**
* load user settings from store in the form
*/
loadSettings: function(){
this.store.load();
var data = this.store.getAt(0).data;
if (Ext.isObject(data)) {
var conf = Ext.ModelMgr.create({
id:1,
language: data.language,
limit: data.limit,
range: data.range
},
'Options'
);
console.log(data);
this.setValues({filters:"",id:1,language:"PT",limit:25,range:10}); // I've tried this.load() too.
}
},
/**
* Save form user settings model in store
*/
saveAction: function() {
var data = this.getValues();
var conf = Ext.ModelMgr.create({
id:1,
language: data.language,
limit: data.limit,
range: data.range
},
'Options'
);
this.store.loadData([]);
this.store.sync();
this.store.add(conf);
this.store.sync();
}
}]
});
...
Home.on('activate',function(){
Options.getComponent('optionsForm').addEventListener();
},this,{single:true});
...
As it turns out, the frameworks is still a bit buggy when it comes to forms and their respective input fields. I ended up creating JSON files to store the data for the translations and used an Ext.Sheet to mask out the Options panel (overcoming another bug). Code below..
...
function include(filename)
{
var head = document.getElementsByTagName('head')[0];
script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';
head.appendChild(script)
}
var text = new Array();
include('app/lang/en.js'); // JSON file with English translation
include('app/lang/pt.js'); // JSON file withe Portuguese translation
function langText(lang,el) {
return text[lang][el];
}
...
var OptionsStorage = JSON.parse(window.localStorage.getItem('f2t-options'));
if(OptionsStorage == null) { //load defaults
OptionsStorage = new Object();
OptionsStorage.language = "EN";
}
window.localStorage.setItem('f2t-options',JSON.stringify(OptionsStorage));
Ext.apply(Ext.MessageBox.YES, {text: langText(OptionsStorage.language,'Yes')});
Ext.apply(Ext.MessageBox.NO, {text: langText(OptionsStorage.language,'No')});
...
var OptionsMask = new Ext.Sheet({
modal:false,
fullscreen:true,
stretchX: true,
stretchY: true,
style:'background:rgba(0,0,0,0.3) !important;', //style like a mask
addEventListener: function(){
this.el.on('click',function(){Options.hide();});
}
});
var Options = new Ext.Panel({
id: 'options',
floating: true,
modal: false,
hideOnMaskTap: false,
listeners:{
beforeshow: function(){
OptionsMask.show();
},
afterrender: function(){
OptionsMask.addEventListener();
},
hide: function(){
OptionsMask.hide();
updateNearby();
}
},
items: [{
xtype: 'form',
id: 'optionsForm',
items: [{
xtype: 'fieldset',
title: langText(OptionsStorage.language,'Language'),
items: [{
xtype: 'selectfield',
name: 'language',
value: OptionsStorage.language,
options: [{
text: 'English',
value: 'EN',
selected: (this.value == OptionsStorage.language)?true:false
}, {
text: 'Português',
value: 'PT',
selected: (this.value == OptionsStorage.language)?true:false
}],
listeners:{
change: function(){
Options.getComponent('optionsForm').saveAction();
// TRANSLATE STUFF
}
}
}]
}]
}]
}],
/**
* Save user settings in localstorage
*/
saveAction: function() {
var data = this.getValues();
OptionsStorage = new Object();
OptionsStorage.language = data.language;
window.localStorage.removeItem('f2t-options');
window.localStorage.setItem('f2t-options',JSON.stringify(OptionsStorage));;
}
}]
});