angularJS 확장 명령 통합 섹션 jquery ui/plugin

13204 단어 AngularJS
최근에 Angularjs를 연구해 왔는데 양방향 귀속이 정말 강하다. 중국어 커뮤니티, 공식 문서를 보면github의 ui 예시를 참고하여angularjs의 개발 방식인 전통적인dom프로그래밍과 완전히 다르다. jquery는 Angularjs의 디자인 이념에서 배후자로서만 날카롭다.AMD/CMD는 angularjs와 함께 사용할 수 있지만 angularjs 자체의 모듈 디자인, 특히 자동 주입 특성은amd/cmd보다 우수하다.jquery plugin의 확장 방식과 같이amd/cmd는 다른 비공식 표준으로 js 확장을 축적하기를 원합니다.angularjs도 마찬가지입니다. 개발자가 선택하거나 조합하거나 취사선택을 해야 합니다.
 
본론으로 돌아가자면 간단하게 cmd 형식으로 확장된angularjs 명령을 붙여 jquery/plugin과 결합시키는 코드를 실현하고 필요한 아동화는 참고할 수 있다. 이 사고방식에 따라 jquery의 유용한 기능을angularjs의 응용에 이식할 수 있다.
 
// file ng.config.js
define(function(require){
	return {
		init: function(){
			//     
			var conf = {};

			conf.date = {dateFormat: 'yy-mm-dd'};
			conf.autocomplete = {minChars: 3, maxItemsToShow: 20};

			var md = angular.module('ng.config', []);
			md.value('ng.config', conf);
		}
	};
});

// file ng.filter.js
define(function(require){
	return {
		init: function(){
			var md = angular.module('ng.filter', []);

			//            。。。  
			// http://stackoverflow.com/questions/11676901/is-this-normal-for-angularjs-filtering

			//       
			md.filter('formatDate', function(){
				return function(value, format){
					if (!value)
						return value;

					return value.format(format || 'yyyy-MM-dd');
				};
			});
		}
	};
});

// file ng.service.js
define(function(require){
	return {
		init: function(){
			var md = angular.module('ng.service', []);

			//     
			//       ,    
			md.factory('uiGetPageData', ['$window', function(win){
				return function(key){
					var pageData = win.pageData;
					return pageData ? pageData[key] : null;
				};
			}]);

			//   
			md.factory('uiLog', ['$window', function(win){
				return function(msg, level){
					if(typeof(msg) != 'string')
						msg = JSON.stringify(msg);

					level = level || 'INFO';
					if(win.console && win.console.log)
						win.console.log('[' + level + ']' + msg);
				};
			}]);

			//       
			md.factory('uiRequest', ['uiLog', function(log){
				return {
					filter: function(params, conf, skipLl){
						if(!conf)
							conf = {dateFormat: 'yyyy-MM-dd'};

						var r = {};
						if(params){
							for(key in params){
								if(skipLl && skipLl.contains(key))
									continue;

								var val = params[key];
								if(angular.isDate(val)){
									r[key] = val.format(conf.dateFormat);
								}else{
									r[key] = val;
								}
							}
						}
						return r;
					}
				};
			}]);

			//     
			md.factory('uiValid', function(){
				return {
					check: function(val, rule){
					}
				};
			});
		}
	};
});

// file ng.ui.js
define(function(require){
	require('ng/ng.config').init();
	require('ng/ng.service').init();
	require('ng/ng.filter').init();

	require('jquery.autocomplete');
	require('jquery.bgiframe');
	require('jquery.datepicker');
	require('jquery.hotkeys');

	var ag = window.angular;
	return {
		init: function(){
			var md = ag.module('ng.ui', ['ng.config', 'ng.service', 'ng.filter']);
			
			//      
			// *** *** *** *** *** *** *** *** *** ***
			// *** *** *** *** *** *** *** *** *** ***
			md.directive('uiDate', ['ng.config', 'uiLog', function(conf, log){
				'use strict';
				var options = {};
				if(ag.isObject(conf.date)){
					ag.extend(options, conf.date);
				}
				return {
					restrict: 'A',
					require: 'ngModel',
					link: function(scope, el, attrs, ctrl){
						var getOptions = function(){
							return ag.extend(options, scope.$eval(attrs.uiDate));
						};

						var init = function(){
							var opts = getOptions();
							log('Init datepicker : ');
							log(opts);

							if(ctrl){
								// update model when datepicker value changes
								var updateModel = function(){
									scope.$apply(function(){
										var date = el.datepicker("getDate");
										ctrl.$setViewValue(date);
									});
								};

								if(opts.onSelect){
									var userHandler = opts.onSelect;
									opts.onSelect = function(value, picker){
										updateModel();
										return userHandler(value, picker);
									};
								}else{
									opts.onSelect = function(value, picker){
										updateModel();
									};
								}

								// datepicker      
//								el.bind('change', updateModel);

								// Update the date picker when the model changes
								ctrl.$render = function(){
									var date = ctrl.$viewValue;
									if (ag.isDefined(date) && date !== null && !ag.isDate(date)){
										throw new Error('ng-Model value must be a Date object - currently it is a ' + typeof date + ' - use ui-date-format to convert it from a string');
									}

									el.datepicker("setDate", date);
								};
							}

							// If we don't destroy the old one it doesn't update properly when the config changes
							el.datepicker('destroy');
							// Create the new datepicker widget
							el.datepicker(opts);
							// Force a render to override whatever is in the input text box
							ctrl.$render();
						};

						// Watch for changes to the directives options
						scope.$watch(getOptions, init, true);
					}
				};
			}]);

			//     
			// *** *** *** *** *** *** *** *** *** ***
			// *** *** *** *** *** *** *** *** *** ***
			md.directive('uiAutocomplete', ['ng.config', 'uiLog', function(conf, log){
				'use strict';
				var options = {};
				if(ag.isObject(conf.autocomplete)){
					ag.extend(options, conf.autocomplete);
				}
				return {
					restrict: 'A',
					require: 'ngModel',
					link: function(scope, el, attrs, ctrl){
						var getOptions = function(){
							return ag.extend(options, scope.$eval(attrs.uiAutocomplete));
						};

						var init = function(){
							var opts = getOptions();
							log('Init autocomplete : ');
							log(opts);

							if(!opts.url || !opts.targetModel){
								log('Init autocomplete fail : url/targetModel required!');
								return;
							}

							if(ctrl){
								ctrl.$render = function(){
									//               ,       
									var showLabel = ctrl.$viewValue;
									if(!showLabel){
										var targetModel = opts.targetModel;

										var showValue;
										if(targetModel.contains('.')){
											var arr = targetModel.split(/\./);
											var i = 0;
											var targetScope = scope;

											for(; i < arr.length; i++){
												var key = arr[i];
												if(i == arr.length - 1){
													showValue = targetScope[key];
												}else{
													if(!targetScope[key])
														break;
													targetScope = targetScope[key];
												}
											}
										}else{
											showValue = scope[targetModel];
										}
										if(showValue){
											ctrl.$setViewValue(showValue);
											el.val(showValue);
										}
									}
								};
							}

							// json : 
							// [{data: {result: i}, value: 'Col' + i}]
							el.autocomplete({
								url: opts.url, 
								minChars: opts.minChars, 
								maxItemsToShow: opts.maxItemsToShow, 
								remoteDataType: 'json', 
								useCache: false,
								processData: function(data) {
									var i, r = [];
									for(i = 0; i < data.length; i++){
										var item = data[i];
										r.push({data: {result: item.v}, value: item.v + '-' + item.l});
									}
									return r;
								},
								onItemSelect: function(item){
									var val = item.data.result;
									var showLabel = item.value;

									var targetModel = opts.targetModel;

									if(targetModel.contains('.')){
										var arr = targetModel.split(/\./);
										var i = 0;
										var targetScope = scope;

										for(; i < arr.length; i++){
											var key = arr[i];
											if(i == arr.length - 1){
												targetScope[key] = val;
											}else{
												if(!targetScope[key])
													targetScope[key] = {};
												targetScope = targetScope[key];
											}
										}
									}else{
										scope[targetModel] = val;
									}

									scope.$apply(function(){
										ctrl.$setViewValue(showLabel);
									});
								}
							});

							ctrl.$render();
						};

						// Watch for changes to the directives options
						scope.$watch(getOptions, init, true);
					}
				};
			}]);

			//    
			// *** *** *** *** *** *** *** *** *** ***
			// *** *** *** *** *** *** *** *** *** ***
			md.directive('uiShortkey', ['ng.config', 'uiLog', function(conf, log){
				'use strict';
				var options = {};
				return {
					restrict: 'A',
					link: function(scope, el, attrs, ctrl){
						var getOptions = function(){
							return ag.extend(options, scope.$eval(attrs.uiShortkey));
						};

						var init = function(){
							var opts = getOptions();
							log('Init shortkey : ');
							log(opts);

							if(!opts.key || !opts.method){
								log('Init shortkey fail : key/method required!');
								return;
							}

							$.hotkeys.add(opts.key, function(){
								var fn = scope[opts.method];
								if(fn)
									fn.call();
							});
						};

						// Watch for changes to the directives options
						scope.$watch(getOptions, init, true);
					}
				};
			}]);

			//     
			// *** *** *** *** *** *** *** *** *** ***
			// *** *** *** *** *** *** *** *** *** ***
			md.directive('uiLayoutCol', ['ng.config', 'uiLog', function(conf, log){
				'use strict';
				return {
					restrict: 'A',
					link: function(scope, el, attrs, ctrl){
						if('TR' != el[0].nodeName)
							return;

						log('Relayout...');

						var _tds = el.children('td');
						if(_tds.size() == 2){
							_tds.filter(':first').addClass('l');
							_tds.filter(':last').addClass('r');
						}else if(_tds.size() == 4){
							_tds.filter(':even').addClass('l2');
							_tds.filter(':odd').addClass('r2');
						}else if(_tds.size() == 6){
							_tds.eq(0).addClass('l3');
							_tds.eq(1).addClass('r3');
							_tds.eq(2).addClass('l3');
							_tds.eq(3).addClass('r3');
							_tds.eq(4).addClass('l3');
							_tds.eq(5).addClass('r3last');
						}

						// siblings tr set td text-align to right if exists label 
						el.siblings('tr').children('td').filter(function(){
							return $(this).find('label').size() > 0;
						}).addClass('ar');

						// set vertical-align = middle for label
			//			el.siblings('tr').children('td').each(function(){
			//				var _td = $(this);
			//				if(_td.find('label').size() > 0){
			//					_td.addClass('ar');
			//					_td.find('label').addClass('vm');
			//				}
			//			});
					}
				};
			}]);
		}
	};
});

 
 

좋은 웹페이지 즐겨찾기