`

angularJS扩展指令集成部分jquery ui/plugin

    博客分类:
  • web
 
阅读更多

最近一直研究angularjs,其双向绑定的确很强大,看中文社区,官方文档,参考github的ui示例,大概摸索下angularjs的开发方式——和传统的dom编程完全不同,jquery再锋利在angularjs的设计理念中,只能作为幕后者。AMD/CMD虽然能和angularjs一起使用,但angularjs自己的module设计,尤其是自动注入特性,比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');
			//				}
			//			});
					}
				};
			}]);
		}
	};
});

 

 

 

分享到:
评论

相关推荐

    jQuery_UI与plugin开发实战

    ### jQuery UI与Plugin开发实战:折叠菜单(Accordion) 在探讨jQuery UI与插件开发实战时,折叠菜单(Accordion)作为一款强大的用户界面组件,凭借其节省空间、易于定制的特性,成为了网页设计中的常用工具。本文...

    jQuery全能权威指南:jQuery Core+jQuery Plugin+jQuery UI+jQuery Mobile 源码

    《jQuery全能权威指南:jQuery Core+jQuery Plugin+jQuery UI+jQuery Mobile》的阅读对象是具有一些HTML 、CSS和JavaScript知识的开发者,内容覆盖了jQuery知识体系的全部内容,包括jQuery Core、jQuery Plugin 、...

    jquery ui 1.7 min高压缩版

    虽然它不是 jQuery UI 的核心部分,但它是一个常见的 jQuery 插件,用于处理表单的异步提交,比如AJAX上传或验证。这个文件很可能包含了一个精简版的 jQuery Form Plugin,这个插件扩展了 jQuery 对象,以便更方便地...

    jQuery ui 日历插件应用实例

    通过研究这些示例,你可以更深入地了解如何集成和定制jQuery UI日历插件,以适应你的项目需求。 总的来说,jQuery UI日历插件是一个强大且灵活的工具,它为网页开发带来了便利的日期选择功能。结合其丰富的配置选项...

    jQuery添加/删除标签插件jQuery Tags Input Plugin

    一个jquery开发的标签功能加强插件,可以生成或删除标签,还能对输入重复标签进行检查,和JQuery autocomplete插件配合实现自动完成功能。演示地址:http://www.jq22.com/jquery-info426

    基于jquery ui的自定义布局(附下载)

    jQuery UI虽然本身并未内置专门的布局插件,但社区中存在一些第三方扩展,例如“jQuery UI Layout”(也称为“UI Layout”或“Layout Plugin”),它基于jQuery和jQuery UI,为开发者提供了一种高效的方式来创建多...

    240多个jQuery UI插件

    ### 240多个jQuery UI插件:详细知识点解析 #### 文件上传(Fileupload) - **文件上传(Fileupload)** - **文件上传插件**主要包括: - **Fileupload**: 提供了强大的文件上传功能,支持多文件上传、进度条显示等...

    jQuery Media Plugin Demo

    jQuery Media Plugin是一款专门为jQuery设计的多媒体插件,用于在网页中轻松集成音频、视频和图像等多媒体元素。这款插件的出现,极大地简化了开发者在HTML5时代处理多媒体内容的复杂性,使得开发者无需深入了解...

    扩展jQuery Media Plugin

    【jQuery Media Plugin扩展详解】 jQuery Media Plugin是一款专为jQuery设计的多媒体播放器插件,它极大地增强了网页中音频和视频的交互性与控制能力。在Web开发中,媒体元素的控制功能是不可或缺的,比如播放、...

    derby_plugin derby_ui_plugin

    Derby Plugin和Derby UI Plugin是专门为Eclipse集成开发环境设计的两个插件,它们极大地扩展了Eclipse在处理Apache Derby数据库方面的功能。Apache Derby是一款轻量级的关系型数据库管理系统,由Java编写,完全符合...

    基于JQuery UI的datepicker二次开发 支持时分秒(带示例)

    这通常涉及到自定义扩展JQuery UI的datepicker插件。在这个案例中,我们可以使用名为`jquery-ym-datePlugin-0.1.js`的文件,这是一个针对日期插件的扩展,增加了时分秒的选择功能。该插件可能通过添加新的选项,如`...

    struts2-jquery-plugin使用手册,自己写的

    Struts2-jQuery-Plugin是基于Struts2框架的一个扩展插件,它为开发者提供了丰富的jQuery UI组件,使得在Struts2应用中实现交互式的用户界面变得更加便捷。这个使用手册将详细阐述如何集成并利用该插件提升Web应用的...

    angularjs -plugin

    2. **AngularJS Plugin for IntelliJ IDEA**:IntelliJ IDEA平台的AngularJS插件,提供强大的代码智能感知和集成开发环境支持。 3. **WebStorm**:JetBrains公司的旗舰级Web开发IDE,内置对AngularJS的全面支持,...

    jQuery摄像头插件jquery-webcam-plugin

    **jQuery摄像头插件jquery-webcam-plugin** 在网页开发中,集成摄像头功能可以帮助用户实时捕捉图像,广泛应用于在线证件照上传、视频聊天、虚拟试衣间等场景。`jQuery webcam plugin`是一个优秀的JavaScript库,它...

    jquery表单UI美化

    3. **插件使用**:jQuery有许多优秀的表单插件,如jQuery UI、Bootstrap、jQuery Validation Plugin等,它们提供了丰富的预设样式和功能,能够快速实现表单美化。 二、jQuery UI美化表单 1. **jQuery UI组件**:...

    JQuery validation plugin学习资料

    **jQuery Validation Plugin 知识详解** jQuery Validation Plugin 是一个用于前端表单验证的强大工具,它为jQuery用户提供了方便快捷的方法来验证用户输入的数据,确保数据的准确性和完整性。这个插件能够帮助...

    jQuery Rater Star Plugin

    总结,jQuery Rater Star Plugin提供了方便快捷的方式来实现星星评价功能,其灵活性和可扩展性使其成为网页开发者的理想选择。通过理解其工作原理和使用方法,开发者可以轻松地在项目中应用这一插件,提升用户体验。

    癞子斗地主源码下载

    最近网上源码难找了,在这里给大家提供一份癞子斗地主源码,可用的哦[img=http://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/001/face/42.gif][/img]!!!在这里先上图给大家参考[img=...

    jquery ui 插件 效果不错

    [Interactions] Draggable Droppable Resizable Selectable Sortable ...These demos showcase some common uses of each jQuery UI plugin. Simply copy and paste code from the demos to get started.

    tableExport.jquery.plugin-1.10.22.zip

    "tableExport.jquery.plugin"是这个插件的核心部分,它的主要功能是将HTML表格转换为不同格式的数据,包括Excel(.xls或.xlsx)、CSV、JSON、SQL等。在1.10.22这个版本中,开发者可能已经修复了一些已知问题,优化了...

Global site tag (gtag.js) - Google Analytics