Form Demo 注解(ST1)

实例地址


1. app.js

App = new Ext.Application({
	name:'App',
	
	launch: function(){
		/*
		 * here: App = this
		 * App.views.viewport = new App.views.Viewport();
		 */
		this.views.viewport = new App.views.Viewport();
		//App.views.viewport = new this.views.Viewport();//worx too
		
		//usersList and usersForm are component name which can be used by App.views['usersList'] or App.views['usersForm']
		this.views.usersList = this.views.viewport.down('#usersList');
		this.views.usersForm = this.views.viewport.down('#usersForm');
	}
});

在app.js中创建2个变量名分别为usersList和usersForm,其namespace为App.views。 比较好的方法是在Viewpor.js中通过Ext.apply创建该两个views,并且加载到viewport的items中去(this.items),具体见(NotesAppMVC/MainView)。


2.Model: User.js

//use App.models.User or Ext.getModel('User') to get this model
App.models.User = Ext.regModel('User',{
	fields:[{
		name: 'id',
		type: 'int'
	},{
		name: 'name',
		type: 'string'
	},{
		name: 'email',
		type: 'string'
	},{
		name: 'phone',
		type: 'string'
	}],
	
	validations:[
		{
			type: 'presence',
			name: 'name'
		},{
			type: 'format',
			name: 'email',
			matcher: /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,
			message: 'must be a valid email'
		}
	],
	
	proxy: {
		type: 'localstorage',
		id: 'sencha-users'
	}
});

App.models.User 是类名,通过 new App.models.User()来创建新的instance. 同时id:“User” 可以在使用ModelMgr中使用。

3. Store: Users.js

App.stores.users = new Ext.data.Store({
    model: 'User',
    autoLoad: true
});


//Uncaught TypeError: Object myStore has no method 'create'
//Uncaught TypeError: Object myStore has no method 'getAt'
// App.stores.users = Ext.regStore("myStore",{
    // model: 'User',
    // autoLoad: true
// });

这里App.stores.users是instance, 在List或者controller中的配置项store中,应该写instance名,而不是类名。

另外可以使用regStore为其分配一个id,但是这样就不能使用this.store.getAt(index) 以及 this.store.create(data)


4. Viewport.js

App.views.Viewport = Ext.extend(Ext.Panel,{
	fullscreen: true,
	layout:'card',
	
	initComponent: function(){
		Ext.apply(this,{
			items:[{
				xtype: 'App.views.UsersList', id: 'usersList'
			},{
				xtype: 'App.views.UsersForm', id: 'usersForm'
			}]
		});
		
		App.views.Viewport.superclass.initComponent.apply(this, arguments);
	},
	
	reveal: function(target) {
		var direction = (target === 'usersList') ? 'right' : 'left';
		// console.log("target: " + target);
		// console.log("direction: " + direction);
		// console.log("App.views: " + App.views[target]);
		//target "usersList" is a component name which is definded with this.views."usersList" = in app.js
		this.setActiveItem(
			App.views[target],
			{ type: 'slide', direction:direction}
		);
	}
});

viewport.js 是规划一个总视图,并且加上2个子视图:UsersList,UsersForm,这里分配的两个id会覆盖类中定义的所用到的id。默认显示第一个items里的视图。


5. Form.js

5.1 结构规划

先构思一下form的结构,最上面是个titlebar,除了title外,最左面有个返回user List的按钮。最下面是个buttonbar, 最左边有个Delete,最右面有个Save。进一步设想一下,Delete按钮何时该出现(新记录不用delete,只有当修改旧记录时才出现),同样新记录时,save按钮不变,如果是修改旧记录,那么就显示update。最后title也要做相应改变。这里都是通过给component一个id,然后通过down/query来找到component,再进行相关配置项的修改。

App.views.UsersForm = Ext.extend(Ext.form.FormPanel, {
	defaultInstructions: 'Please enter the information above',
	
	initComponent: function(){
		var titlebar, cancelButton, buttonbar, saveButton, deleteButton, fields;
		
		cancelButton = {
			text: 'cancel',
			ui: 'back',
			handler: this.onCancelAction,
			scope: this
		};
		
		titlebar = {
			id:'userFormTitlebar',
			xtype: 'toolbar',
			title: 'Create user',
			items: [cancelButton]
		};
		
		saveButton = {
			id: 'userFormSaveButton',
			text: 'save',
			ui: 'confirm',
			handler: this.onSaveAction,
			scope: this
		};
		//can't call deleteButton.hide()
		deleteButton = {
			id: 'userFormDeleteButton',
			text: 'delete',
			ui: 'decline',
			handler: this.onDeleteAction,
			scope: this
		};
		
		buttonbar = {
			xtype: 'toolbar',
			dock: 'bottom',
			//deleteButton become a button in toolbar
			items: [deleteButton, {xtype:'spacer'}, saveButton]
		};
		
		fields = {
			xtype: 'fieldset',
			id: 'userFormFieldset',
			title: 'User details',
			instructions: this.defaultInstructions,
			defaults:{
				xtype: 'textfield',
				labelAlign: 'left',
				labelWidth: '40%',
				required: false,
				useClearIcon: true,//Deprecated since 2.0, use clearIcon instead
				autoCapitalize: false
			},
			items:[{
				name: 'name',
				label: 'name',
				autoCapitalize: true//Chrome and Safari on desktop won't use this attribute, so no effect to show off
			},{
				xtype:'App.views.ErrorField',
				fieldname: 'name'
			},{
				name: 'email',
				label: 'email',
				xtype: 'emailfield'
			},{
				xtype: 'App.views.ErrorField',
				fieldname: 'email'
			},{
				name: 'phone',
				label: 'phone',
				xtype: 'numberfield'
			},{
				xtype: 'App.views.ErrorField',
				fieldname: 'phone'
			}]
		}
		
		Ext.apply(this, {
			scroll: 'vertical',
			dockedItems:[titlebar, buttonbar],
			items:[fields],
			listeners: {
				//Fires before a Component has been visually activated.
				beforeactivate: function(){
					//get button component by using this.down(selector)
					var deleteButton = this.down('#userFormDeleteButton'),
						saveButton = this.down('#userFormSaveButton'),
						titlebar = this.down('#userFormTitlebar'),
						model = this.getRecord();
					
					if(model.phantom) {
						titlebar.setTitle('Create user');
						saveButton.setText('create');
						deleteButton.hide();
					}else{
						titlebar.setTitle('Update user');
						saveButton.setText('update');
						//this.deleteButton is the class variable, never defined
						//deleteButton is a variable in initComponent defined.
						//console.log(deleteButton.id);//worx
						deleteButton.show();
					}
				},
				//Fires after a Component has been visually deactivated.
				deactivate: function(){
					this.resetForm();
				}
			}
		});
		
		App.views.UsersForm.superclass.initComponent.call(this);
	},

先把各个部件在initComponent中分别定义,然后添加到Ext.apply中。

5.2 函数定义

	onCancelAction: function(){
		Ext.dispatch({
			controller: 'Users',
			action: 'index'
		});
	},
	
	onSaveAction: function(){
		
		//console.log("object: " + this.id);
                //this reference to usersForm because scope:this (by this save button)
                //if scope not set, then this reference to the savebutton not formPanel
		var model = this.getRecord();
		Ext.dispatch({
			controller: 'Users',
			action: (model).phantom ? 'save' : 'update',
			data: this.getValues(),
			record: model, //Ext.FormPanel.getRecord() returns the Model instance currently loaded into this form(if any)
			form: this
		})
	},
	
	onDeleteAction: function(){
		Ext.Msg.confirm("Delete this user?", "", function(answer){
			if(answer === 'yes') {
				Ext.dispatch({
					controller: 'Users',
					action: 'remove',
					record: this.getRecord()
				});
			}
		},this);
	},
	
	showErrors: function(errors){
		var fieldset = this.down('#userFormFieldset');
		//console.log("this.fields: " + this.fields.items[0].name);//worx
		
		//this.fields has 3 items and each item is afield
		this.fields.each(function(field){
			//getByField is funk of Ext.data.Errors, return all errors(Array) for the given field
			var fieldErrors = errors.getByField(field.name);
			
			if(fieldErrors.length > 0){
				var errorField = this.down('#'+field.name+'ErrorField');
				field.addCls('invalid-field');
				//Update the content area of a component(errorField). e.g. it shows both in errorfield
				//var d = new Array({field:'dd',message:'dds'},{field:'dds',message:'ddss'});
				//errorField.update(d);
				
				errorField.update(fieldErrors);//but here only show message of Array fieldErrors
				//console.log("fieldErrors: " + fieldErrors[0].field);//worx
				//console.log("fieldErrors: " + fieldErrors[0].message);//worx
				errorField.show();
			}else{
				this.resetField(field);
			}
		}, this);
		fieldset.setInstructions('Please amend the flagged fields');
	},
	
	resetField: function(field){
		var errorField = this.down('#'+field.name+'ErrorField');
		errorField.hide();
		field.removeCls('invalid-field');
		return errorField;//need this?
	},
	
	resetForm: function(){
		//reset all error fields
		var fieldset = this.down('#userFormFieldset');
		this.fields.each(function(field){
			this.resetField(field);
		},this);
		fieldset.setInstructions(this.defaultInstructions);
		//reset all normal fields
		this.reset();
	}
	
});

Ext.reg('App.views.UsersForm', App.views.UsersForm);

6. List.js

App.views.UsersList = Ext.extend(Ext.Panel, {
	
	initComponent: function(){
		var addButton, titlebar, list;
		
		addButton = {
			itemId: 'addButton',
			iconCls: 'add',
			iconMask: true,
			ui: 'plain',
			handler: this.onAddAction,
			scope: this
		};
		
		titlebar = {
			dock: 'top',
			xtype: 'toolbar',
			title: 'Users',
			items: [{
				xtype: 'spacer'
			}, 
			addButton
			]
		};
		
		list = {
			xtype: 'list',
			itemTpl: '{name}',
			store: App.stores.users,
			//store: 'myStore',
			listeners:{
				scope:this,
				itemtap:this.onItemtapAction
			}
		};
		
		Ext.apply(this, {
			html: 'placeholder',
			layout: 'fit',
			dockedItems: [titlebar],
			items: [list]
		});
		
		App.views.UsersList.superclass.initComponent.call(this);
	},
	
	onAddAction: function(){
		Ext.dispatch({
			controller: 'Users',
			action: 'newForm'
		});
	},
	
	onItemtapAction: function(obj, index, item, e){
		Ext.dispatch({
			controller: 'Users',
			action: 'editForm',
			index: index
		})
	}
});

Ext.reg('App.views.UsersList', App.views.UsersList);

7. ErrorField.js

App.views.ErrorField = Ext.extend(Ext.Component, {
	initComponent: function() {
		config = {
			xtype: 'component',
			id: this.fieldname + 'ErrorField',
			cls: 'errorfield',
			tpl: [
				'<tpl if="values.length > 0">',
				'   <ul>',
				'      <tpl for=".">',
				'          <li>{message}</li>',
				'      </tpl>',
				'   </ul>',
				'</tpl>'
			],
			hidden: true
		};
		
		Ext.apply(this, config);
		App.views.ErrorField.superclass.initComponent.call(this);
	}
});

Ext.reg('App.views.ErrorField', App.views.ErrorField);

8. Controller

Ext.regController('Users',{
	store: App.stores.users,
	//store: 'myStore',
	//this.application.views.viewport worx only if this app is created by Ext.regAppliction
	index: function(){
		App.views.viewport.reveal('usersList');
	},
	
	newForm: function(){
		var model = new App.models.User();
		App.views.usersForm.load(model);
		App.views.viewport.reveal('usersForm');
	},
	
	editForm: function(params){
		var model = this.store.getAt(params.index);
		App.views.usersForm.load(model);
		App.views.viewport.reveal('usersForm');
	},
	
	save: function(params){
		//console.log("before: " + params.record.data.name);
		//make sure before calling model.validate(), new data has been set into model.
		params.record.set(params.data);
		//console.log("after: " + params.record.data.name);
		var errors = params.record.validate();
		if(errors.isValid()){
			//sava data in the store, this.store.create can only be used when App.stores.users = new Ext.data.Store({})
			//not App.stores.users = Ext.regStore()
			this.store.create(params.data);
			//this.store.create(params.record.data);//worx too
			this.index();
		}else{
			//errors is mixed Object with items which includes each error field
			params.form.showErrors(errors);
		}
		
	},
	
	update: function(params){
		var tmpUser = new App.models.User(params.data),
			errors = tmpUser.validate();
		if(errors.isValid())	
		{
			
                        //bug here, if refresh page, show old record too
                        //params.record.set(params.data);
			//params.record.save();
                          params.form.updateRecord(params.model);
                          this.store.sync();
                          this.index();
		}else{
			params.form.showErrors(errors);
		}
	},
	
	remove: function(params){
		this.store.remove(params.record);
		this.store.sync();
		this.index();	
	}
});


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值