자바스크립트/Ext JS2013. 9. 17. 20:13

ExtJS MVC구조를 통해 어플리케이션을 개발시 고민 중 하나가 컨트롤러의 등록이다. 

보통에 경우 app.js 즉 Ext.Application을 상속받은 클래스에 사용할 Controller를 등록하게 된다.


그러나 개발 시에는 매번 생성되는 컨트롤러를 app.js에 등록 하기 어렵고? 아니 귀찮고 규모가 큰 시스템에 경우

컨트롤러도 많아 지게 되어 모두 등록한다는 것 자체가 왠지 성능상에 좋지 않을 듯 싶다.


해서 생각한 것이 다이나믹하게 컨트롤러를 그때 그때 등록할수 있는 방법을 사용하게 된다.

대충 기술하자면 한개 정도의 미리 등록된 컨트롤러가 참조하고 있는 뷰를 통해 해당 컨트롤러에 

접근하면서 사용할 컨트롤러의 이름을 전달하고 접근과 동시에 application클래스에 특정 메소드를 호출하여

아래와 같이 새로운 컨트롤러를 등록하도록 하였다.

application안에서 컨트롤러를 등록하는 방법은 

var controller = this.getController('사용할 컨트롤러 클래스명');

controller.init(this); -> 여기서 this는 어플리케이션 클래스 이다.


문제는 이때 발생한다. 개발 모드에서 다이나믹하게 컨트롤러를 등록하여 사용할 수 있는 코드는 구축이 되었지만

실서버에 배포할 요량으로 빌드를 해보니 app.js에 등록되지 않은 컨트롤러는 빌드에서 빠지는 현상이 발생한다.


이는 ExtJS가 클래스의 종속성에 대해 검증하는 과정에서 사용되지 않는 즉 require가 없거나 참조관계 등이 없을 경우

실제 클래스 파일이 존재하는데도 빌드에서는 제외 시킨다는 것이다.


이 경우에는 Sencha Cmd로 생성한 어플리케이션 내의 build.xml파일을 수정하여 언제 사용될지 모르나 이미 존재하는 클래스를

빌드에 포함시키도록 할 수 있다.



어플리케이션 클래스
Ext.application({
    name: 'MyApp',
    appFolder: 'app',

    controllers: [
        "main.App"
    ],

    uses: [
        /*ant-generated-content-start*/ /*ant-generated-content-end*/
    ],

    autoCreateViewport: true,
});
build.xml

    

    

        
        
            
        
        
            
                
                
                    
                    
                        
                        
                    
                
            
        
        

        
        
    

    
        
        
    


참고 : http://stackoverflow.com/questions/14457508/using-sencha-cmd-with-dynamically-loaded-controllers
Posted by 베니94
자바스크립트/Ext JS2013. 7. 3. 09:37

ExtJS로 뭘하나 만들어 볼까 싶어서 몇일 만지작 거리다.


집에 안쓰고 모셔놓은 HP미니 서버를 좀 활용해 사이트를 올려 봅니다.


아직 작업하는 중이고 미완성입니다.


좀 완성도를 높여 상시적으로 Q&A게시판으로 활용하고 


소스는 강좌를 통해 공개하려고 합니다.


주소 : http://benney.able.or.kr



Posted by 베니94
자바스크립트/Ext JS2013. 6. 24. 23:40

안녕하세요 ExtJS 3번째 오프라인 강좌로 "ExtJS Class System & MVC 알아보기"를 
준비 했습니다.

ExtJS만의 클래스 시스템과 MVC 패턴을 통한 구현 방법을 알아보고 실무에 사용되는 
유용한 팁도 공유합니다. 

[강사소개]

    • 삼성SDS ExtJS 강의 수행
    • 한국센챠유저그룹 활동
    • 온오프믹스 ExtJS 강의 진행
    • ExtJS를 적용하여 다수의 시스템 구축 경험
    • Blog : http://benney.tistory.com

[세부 내역]

  • 대상 : ExtJS 초, 중급, ExtJs에 관심 있는 모든분들.
  • 일시 : 6월 29일(토) 17:00 ~ 19:00
  • 장소 : 토즈 강남 2호점(타워점 아닙니다.)
    • URL : http://www.toz.co.kr/branch/main/index.htm?id=11
  • 등록비용 : 50,000원
  • 등록하기 (http://onoffmix.com/event/16084)
  • 강의방식 : 준비 된 샘플을 통한 진행(실습아님)
  • 강의내용
    • ExtJS Class System
      1. Define & Create
      2. Config
      3. Extend & Mixins
      4. Static
      5. Dynamic Class Loading
    • ExtJS MVC의 소개
      1. MVC란 무엇인가?
      2. MVC를 통해 무엇을 얻을 수 있나?
      3. 각 요소에 대한 샘플을 보고 역할을 알 수 있다.
      4. Controller는 만능인가? 알고 쓰자 Controller


    • 기타 문의는 benneykwag@gmail.com으로 해주세요

      종료 후 뒷풀이를 하려고 합니다. 참석하신다는 분들이 있으면요 ^^
      (비용은 부담되지 않는 선에서 나누어 내도록 하시지요)


Posted by 베니94
자바스크립트/Ext JS2013. 5. 25. 14:22

ExtJs 4.2 버전에서 전에 없던 툴팁 버그가 발생한다. 아래 그림과 같이 툴팁의 길이가 동적으로 늘어나지 않고 

텍스트가 일정크기 이상으로 늘어나지 않고 갇히게 된다.



이를 해결하기 위해 아래와 같이 Ext.tip.QuickTip클래스를 override한다.


Ext.override(Ext.tip.QuickTip, {
    helperElId: 'ext-quicktips-tip-helper',
    initComponent: function ()
    {
        var me = this;


        me.target = me.target || Ext.getDoc();
        me.targets = me.targets || {};
        me.callParent();


        // new stuff
        me.on('move', function ()
        {
            var offset = me.hasCls('x-tip-form-invalid') ? 35 : 12,
                helperEl = Ext.fly(me.helperElId) || Ext.fly(
                    Ext.DomHelper.createDom({
                        tag: 'div',
                        id: me.helperElId,
                        style: {
                            position: 'absolute',
                            left: '-1000px',
                            top: '-1000px',
                            'font-size': '12px',
                            'font-family': 'tahoma, arial, verdana, sans-serif'
                        }
                    }, Ext.getBody())
                );

            if (me.html && (me.html !== helperEl.getHTML() 
            		|| me.getWidth() !== (helperEl.dom.clientWidth + offset)))
            {
                helperEl.update(me.html);
                me.setWidth(Ext.Number.constrain(helperEl.dom.clientWidth + 
                	offset, me.minWidth, me.maxWidth));
            }
        }, this);
    }
});

적용 이후 아래와 같이 정상적으로 툴팁이 보여진다.


// 출처 : http://stackoverflow.com/questions/15834689/extjs-4-2-tooltips-not-wide-enough-to-see-contents

Posted by 베니94
자바스크립트/Ext JS2013. 5. 22. 16:28
Ext.onReady(function() {
	/***
	 * Date : 2013.05.22
	 * Desc : 아래 코드는 Ext.form.field.Text클래스를 override를 통해 기능을 변경한 예제이다.
	 * 
	 * 		 
	 */
	Ext.define('Cookbook.overrides.TextField', {
		override: 'Ext.form.field.Text',

		onRender: function(){
			/***
			 *  기존 함수의 동작을 확장하기 위해 callParent를 사용한다.
			 *  이때 필요한 인수를 전달하여 원래 함수를 호출할 수 있다.
			 *  아래는 단순히 텍스트를 추가하는 방법을 보여준다.
			 *  간단하게 onRender함수 실행시 간단한 텍스트를 모든 텍스트에서
			 *  동일하게 표시할 수 있도록 되었다.
			 */
			this.callParent(arguments); // executes the Ext.form.field.Text.onRender function
			// Ext.form.field.Text.superclass.onRender.apply(this, arguments); // executes the Ext.form.field.Base.onRender function

			Ext.core.DomHelper.append(this.el, '
' + this.infoText + '
'); } }); Ext.application({ name: 'Customer', launch: function(){ Ext.create('Ext.container.Viewport', { layout: 'fit', items: [{ xtype: 'form', title: 'Security Question Form', defaultType: 'textfield', items: [{ fieldLabel: 'Security Question', name: 'securityQuestion', allowBlank: false, infoText: 'You are required to write a security question for your account.' }, { fieldLabel: 'Security Answer', name: 'securityAnswer', allowBlank: false, infoText: 'Please provide the answer to your security question.' }] }] }); } }); }); // 출처 : Ext JS4 Web Application Development Cookbook
Posted by 베니94
자바스크립트/Ext JS2013. 5. 22. 16:27
Ext.onReady(function() {
	/***
	 * Date : 2013.05.22
	 * Desc : Override Ext JS functionality
	 * 		  당신이 ExtJS 프레임웍의 동작을 변경하고자 한다면(권장하지 않음)
	 * 		  직접 프레임웍을 편집하지 않고 override를 이용해여 당신이 만든 클래스를 
	 * 		  통해 쉽게 제어 또는 변경할 수 있다.
	 * 
	 * 		  프레임 워크 코드를 변경하는 것은 강력하게 다른 개발자로 권장하지되는 것은 
	 * 		  변경을 실현하지 않을 수 있으며 불쾌 표준이 아닌 행동에 의해 놀라게 될!
	 * 
	 * 		  override는 기존의 클래스를 가지고도 기존 기능의 동작을 수정하거나 완전히
	 * 		  새로운 것들을 추가 할 수 있습니다. 이것은 크게 프레임워크의 완전히 밖으로 
	 * 		  상자의 동작을 변경하는
	 * 		  매우 간단한 방법을 제공하기 때문이다.
	 * 
	 * 		  Ext JS override는 Ext.Base.override를 칭한다.
	 * 		  Ext.override(Object originalCls, Object overrides) 오리지날 클래스와 합치길 원하는
	 * 		  클래스를 지정하므로서 두개의 클래스가 병합된다.
	 */
	Ext.define('Simple.Class', {
		welcome : function() {
			alert('Welcome to the app');
		}
	});

//	Simple.Class.override({
//		goodBye : function() {
//			alert('Goodbye');
//		},
//
//		runAll : function() {
//			this.welcome();
//			this.goodBye();
//		}
//	});

	Ext.override(Simple.Class, {
		goodBye : function() {
			alert('Goodbye');
		},

		runAll : function() {
			this.welcome();
			this.goodBye();
		}
	});

	var app = new Simple.Class();
	app.runAll(); // Welcome to the app
	// Goodbye

});

// 출처 : Ext JS4 Web Application Development Cookbook
Posted by 베니94
자바스크립트/Ext JS2013. 5. 22. 16:25
Ext.onReady(function() {
	Ext.define('Cookbook.DisplayPanel', {

		extend : 'Ext.panel.Panel',

		initComponent : function() {

			// apply our configuration to the class
			Ext.apply(this, {
				title : 'Display Panel',
				html : 'Display some information here!',
				width : 200,
				height : 200,
				renderTo : Ext.getBody()
			});

			// call the extended class' initComponent method
			this.callParent(arguments);
		}

	}, function() {
		console.log('Cookbook.DisplayPanel defined!');
	});

	var displayPanel = Ext.create('Cookbook.DisplayPanel');
	displayPanel.show();

	// define our Cookbook.InfoTextField class
	Ext.define('Cookbook.InfoTextField', {

		extend : 'Ext.form.field.Text',
		/***
		 * override했고 this.callparent를 호출하여.
		 * 바로 부모클래스의 onRender메소드가 실행되도록 하였다.
		 */
		onRender : function() {
			this.callParent(arguments);

			// insert our Info Text element
			Ext.core.DomHelper.append(this.getEl(), '
' + this.infoText + '
'); } }, function() { console.log('Cookbook.InfoTextField defined!'); }); // create an instance of our Cookbook.InfoTextField var infoTextField = Ext.create('Cookbook.InfoTextField', { renderTo : Ext.getBody(), fieldLabel : 'Username', infoText : 'Your Username must be at least 6 characters long.' }); // infoTextField.show(); }); // 출처 : Ext JS4 Web Application Development Cookbook
Posted by 베니94
자바스크립트/Ext JS2013. 5. 22. 16:23
Ext.onReady(function() {
	/***
	 * 인스턴스를 검색하는 함수는 총 4가지다.
	 * query, child, up and down.
	 */
	var panel = Ext.create('Ext.panel.Panel', {
		height : 500,
		width : 500,
		renderTo : Ext.getBody(),
		margin : 50,
		id : 'myPanel',
		layout : {
			type : 'vbox',
			align : 'stretch'
		},
		items : [ {
			xtype : 'tabpanel',
			itemId : 'mainTabPanel',
			flex : 1,
			items : [ {
				xtype : 'panel',
				title : 'Users',
				id : 'usersPanel',
				layout : {
					type : 'vbox',
					align : 'stretch'
				},
				tbar : [ {
					xtype : 'button',
					text : 'Edit',
					itemId : 'editButton'
				} ],
				items : [ {
					xtype : 'form',
					border : 0,
					items : [ {
						xtype : 'textfield',
						fieldLabel : 'Name',
						allowBlank : false
					}, {
						xtype : 'textfield',
						fieldLabel : 'Email',
						allowBlank : false
					} ],
					buttons : [ {
						xtype : 'button',
						text : 'Save',
						action : 'saveUser',
						listeners : {
							click : function(){
								// 메소드의 실행이 가능하다.
								// 아래에 경우 리턴되는 객체가 없을 것이다.
								// 해당 텍스트필드에 값이 들어가 있다면 isValid조건에 맞는 객체를 리턴하게 될것이다.
								// 텍스트 필드에 값을 입력 후 Save버튼을 클릭해본다.
								var validField = Ext.ComponentQuery
										.query('form > textfield{isValid()}');
								console.log(validField);
							}
						}
					} ]
				}, {
					xtype : 'grid',
					flex : 1,
					border : 0,
					columns : [ {
						header : 'Name',
						dataIndex : 'Name',
						flex : 1
					}, {
						header : 'Email',
						dataIndex : 'Email'
					} ],
					store : Ext.create('Ext.data.Store', {
						fields : [ 'Name', 'Email' ],
						data : [ {
							Name : 'Joe Bloggs',
							Email : 'joe@example.com'
						}, {
							Name : 'Jane Doe',
							Email : 'jane@example.com'
						} ]
					})
				} ]
			} ]
		}, {
			xtype : 'component',
			itemId : 'footerComponent',
			html : 'Footer Information',
			extraOptions : {
				option1 : 'test',
				option2 : 'test'
			},
			height : 40
		} ]
	});

	// Ext.ComponentQuery's 'query' method
	/***
	 * ComponentQuery는 down, up과는 달리 해당되는 조건의
	 * component를 모두 찾아리턴한다.
	 */
	// Get all Panels
	var panels = Ext.ComponentQuery.query('panel');
//	console.log(panels);
	
	var formPanel = Ext.ComponentQuery.query('form');
	console.log(formPanel);
	// get all Buttons that are descendents of a Panel
	var buttons = Ext.ComponentQuery.query('button');
//	console.log(buttons);

	// get specific Button based on 'action' property
	var saveButton = Ext.ComponentQuery
			.query('button[action="saveUser"]')[0];
//	console.log(saveButton);

	// get 2 types of Component (buttons and textfields)
	var buttonsAndTextfields = Ext.ComponentQuery
			.query('button, textfield');
//	console.log(buttonsAndTextfields);
//
//	// get specific Panel based on ID
	// ID기반 검색.
	var usersPanel = Ext.ComponentQuery.query('panel#usersPanel')[0]; // or
	// Ext.ComponentQuery.query('#usersPanel');
//	console.log(usersPanel);

	// get components that have 'extraOptions' property with any value
	/***
	 * component중에 extraOption속성을 가지고 있는 콤포넌트를 찾아라.
	 * 속성의 존재여부에 따른 검색.
	 */
	var extraOptionsComponents = Ext.ComponentQuery
			.query('component[extraOptions]');
	// 달리 사용하면 component[height] -> 검색가능
	// component[height=40] -> 검색 가능.
//	console.log(extraOptionsComponents);

	

	// myPanel이라는 아이디를 가진 인스턴스를 찾아 하위에 있는 모든 패널을 찾는다. child 밑에 child까지.
	var validField = Ext.ComponentQuery
			.query('#myPanel panel');
//	console.log(validField);
	// myPanel이라는 아이디를 가진 인스턴스를 찾아 하위에 바로 붙어있는 child를 찾는다.
	var validField = Ext.ComponentQuery
			.query('#myPanel > panel');
//	console.log(validField);

	// Ext.ComponentQuery's 'is' method

	// decide if main Panel is a panel
	// 아래 부터는 인스턴스의 유형을 비교한다.
	var isPanel = Ext.ComponentQuery.is(panel, 'panel');
//	console.log(isPanel); // true

	// decide if main Panel is a panel with an ID of 'myPanel'
	// 비교 대상인 인스턴스가 panel이고 id가 myPanel인가?
	var isPanelWithCorrectID = Ext.ComponentQuery.is(panel,
			'panel[id="myPanel"]');
//	console.log(isPanelWithCorrectID); 

	// Container's 'query' method

	// get all buttons under Users Panel
	var usersPanelButtons = usersPanel.query('button');
//	console.log(usersPanelButtons);

	// Container's 'down' method

	// get first Panel under the main Panel (panel)
	var firstChildPanel = panel.down('panel');
//	console.log('001', firstChildPanel);

	// Container's 'child' method
//
//	// get first child button under the main Panel
//	var childButton = panel.child('button');
//	console.log(childButton); // is no Button in first level so
//								// returns null
//
//	// Container's 'up' method
//
//	// get first Panel above 'Add Order' button
	var saveUserButon = Ext.ComponentQuery
			.query('button[action="saveUser"]')[0];
	var saveUserButonParentPanel = saveUserButon.up('panel');

//	console.log(saveUserButonParentPanel);

	// Pseudo-selectors

	// get last textfield
	var lastTextfield = Ext.ComponentQuery.query('textfield:last');
	console.log(lastTextfield);

	// define your own that returns visible components
	Ext.ComponentQuery.pseudos.visible = function(items) {
		console.log('ii', items)
		var result = [];

		for ( var i = 0; i < items.length; i++) {

			if (items[i].isVisible()) {
				result.push(items[i]);
			}
		}

		return result;
	};
	var visibleComponents = Ext.ComponentQuery
			.query('component:visible');
//	console.log(visibleComponents);

});
// 출처 : Ext JS4 Web Application Development Cookbook
Posted by 베니94
자바스크립트/Ext JS2013. 5. 22. 16:22
Ext.onReady(function() {
	Ext.define('Customer.support.SupportMessage', {
        extend: 'Ext.panel.Panel',
        alias: 'widget.supportMessage',
        title: 'Customer Support',
        html: 'Customer support is online'
    });
    
    Ext.application({
        name: 'Customer',
        launch: function(){
            Ext.create('Ext.container.Viewport', {
                layout: 'fit',
                items: [{
                    xtype: 'supportMessage'
                }]
            });
        }
    });
	
});
// 출처 : Ext JS4 Web Application Development Cookbook
Posted by 베니94
자바스크립트/Ext JS2013. 5. 22. 01:22
// Configure the Ext.Loader class
Ext.Loader.setConfig({
	enabled : true,
	paths : {
		'Cookbook' : 'src/Cookbook'
	}
});
Ext.onReady(function() {
	// 동적 로딩 클래스에 대한 예제이다.
	// 상단에서 path를 잡아주었고 하단에서 require하면
	// 팔요한 클래스가 로딩되어 사용이 가능해 진다.
	// 단지 이러한 동적클래스 로딩은 개발모드에서 사용되어 진다고 봐야한다.
	// 운영환경에서는 정적으로 모든 클래스를 로딩할 수 밖에 없는 환경이므로(압축 및 최적화)..
	// 또한 아래와 같이 할 경우 인스펙터 상의 'Elements탭'의 html에서 자동으로 자바스크립트 링크가 
	// 생성된 것을 확인할 수 있다.
	// Create an instance of the Cookbook.Vehicle class inside the Ext.require() callback
	Ext.require('Cookbook.Vehicle', function() { // 이 부분이 있고 없고에 따라
//		var plane = Ext.create('Cookbook.Vehicle', 'Ford', 'Transit', 60);
//		plane.travel(200);
	});
//
//	// Create an instance of the Cookbook.Plane class inside the Ext.require() callback
//	Ext.require('Cookbook.Plane', function() {
//		var plane = Ext.create('Cookbook.Plane', 'Boeing', '747', 500, 35000);
//		plane.travel(200);
//	});
});
// 출처 : Ext JS4 Web Application Development Cookbook

require를 통해 로딩된 클래스 파일을 확인 할 수 있다.


아래 그림은 예제소스를 실행하고 있는 html파일의 내용이다. 위의 인스펙터와는 달리 Vehicle.js를 불러오고 있지 않다는 것을

확인 할 수 있다.



Posted by 베니94