在CodeProject上,发布了一个Angular购物车项目,现在网站www.Software-rus.com上也能找到最新版本的Angular购物车和编辑器。目标是创建一个简单的Angular编辑器,使用户能够对JSON文件或本地/远程数据库执行创建、读取、更新和删除(CRUD)操作。最初,考虑使用数据网格(datagrid)来展示产品,用户可以通过选择数据网格中的一行来编辑产品,但很快发现数据网格会占用太多屏幕空间,所以决定采用不同的GUI布局。将用于选择要编辑的产品的GUI组件放在屏幕左侧的侧边栏中,使用一个简单的列表,而将更大的屏幕区域用于展示每个产品属性,如下所示。喜欢这种布局和方法,它比数据网格更适合编辑器,并且可以应用于编辑任何JSON文件或数据库。每个记录的字段显示在主视图editor-details.htm中。当在侧边栏中选择一个项目时,主视图会更新以显示所选项目的记录。
用户可以轻松修改此编辑器如何从不同的数据源加载和保存数据。方法允许用户在配置文件中设置默认数据源,然后从下拉菜单中选择要加载数据的数据源,如下所示。使用了一个DataService来异步加载数据,它使用promise和deferred。在Angular中,promise充当一个占位符,JavaScript对象从其中返回一些结果作为数据,这是以异步方式完成的,并且不保证任何固定的响应时间。使用$q.defer()构建的deferred对象用于通知异步工作的成功或不成功的完成。在deferred对象完成任务后,可以在promise对象中访问结果。加载数据的Angular代码如下所示:
// JavaScript
storeApp.factory('DataService', function($http, $q, CONFIG) {
// 可以从JSON文件、本地.mdf数据库或远程数据库加载
'CF_DATA_FILE': 'ac_products/products.js',
'CF_DATA_LOCAL': '/crud.ashx?ac=getproducts&cn=local',
'CF_DATA_REMOTE': '/crud.ashx?ac=getproducts&cn=remote',
var dataIndex = localStorage["data_src_index"];
if (dataIndex == null || dataIndex == "undefined") {
dataIndex = 0; localStorage["data_src_index"] = 0;
}
var dataSource = CONFIG.CF_DATA_FILE;
if (dataIndex == 0) {
// 随机化字符串以防止缓存
dataSource = "/" + CONFIG.CF_DATA_FILE + "?rnd=" + new Date().getTime();
} else if (dataIndex == 1) {
dataSource = CONFIG.CF_DATA_LOCAL;
} else if (dataIndex == 2) {
dataSource = CONFIG.CF_DATA_REMOTE;
}
function Store() {
var productsDeferred = $q.defer();
this.products = productsDeferred.promise;
// this.products是一个promise
$http.get(dataSource).success(function(data, status, headers, config) {
var products = [];
for (var i = 0, len = data.length; i < len; i++) {
var prod = data[i];
if (prod.storeid == "7cc6cb94-0938-4675-b84e-6b97ada53978") {
var _expecteddate = new Date(prod.expecteddate);
prod.expecteddate = _expecteddate; products.push(prod);
}
}
productsDeferred.resolve(products);
}).error(function(data, status, headers, config) {
alert("Please check you have updated ConnectionString with YOUR OWN information!");
// 请更新"remoteCartConnectionString"为自己的数据 !!!
});
// ...等等。
}
return new Store();
});
决定将JSON文件中的Date字段加载为Date对象,如下所示:
// JavaScript
var _expecteddate = new Date(prod.expecteddate);
prod.expecteddate = _expecteddate;
在本编辑器中使用的Bootstrap 3菜单在之前的购物车文章中已经详细讨论过,因此不会在这里重复讨论所有代码。可以升级到更高版本的Bootstrap以获得导航栏,并且可以在Bootstrap 3以上版本中使用导航栏代码,而不使用ui-bootstrap,如下所示:
// HTML
<li class="dropdown" ng-class="{open1: open1}">
<a ng-click="navCollapsed = !navCollapsed" href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
<span class="fa fa-cart-plus"></span> Shopping Carts
<span class="caret"></span>
</a>
<ul role="menu" class="dropdown-menu">
<li>
<a ng-click="open1=!open1" ng-href="some url" target="_blank">
<img src="admin_img/codeproject.png" description=''/>
Shopping Cart Article & Source Code
</a>
</li>
</ul>
</li>
在购物车中,有几个字段,如shortdesc、description、carousel_caption和productname,可以有HTML格式,所以决定为这些字段添加一个非常简单的编辑器,称为nng-wig。可以在http://ngmodules.org/modules/ngWig上获得这个模块。重要的是,这些字段不包含任何段落标签或复杂的HTML,这可能会扭曲购物车的外观,所以将编辑限制为加粗、斜体和<br />用于换行。查看了一些用于编辑HTML内容的模块,但其他编辑器插入了太多不必要的HTML格式,这可能会扭曲购物车中的显示。
一直认为一张图片胜过千言万语,但视频胜过百万言。因此,在Angular购物车中,包括了插入图片或视频的功能。值得注意的是,现在有很多视频管服务,从Vimeo到中国巨大的YouKu Tube Server,它现在是世界上最大的电视网络。
// JavaScript
storeApp.directive('embedVideo', function($sce) {
return {
restrict: 'EA',
scope: { tube: '=', code: '='},
replace: true,
template: '<div class="video"><iframe src="{{url}}" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></div>',
link: function (scope) {
scope.url = "about:blank";
scope.$watch('code', function (videoidVal) {
if (videoidVal) {
if (scope.tube === 'youtube') {
scope.url = $sce.trustAsResourceUrl("http://www.youtube.com/embed/" + videoidVal);
} else if (scope.tube === 'youku') {
scope.url = $sce.trustAsResourceUrl("http://player.youku.com/embed/" + videoidVal);
} else if .....等等。
// 其他管
}
scope.$apply();
});
}
};
});
// JavaScript
$scope.uploadFile = function(event) {
var fd = new FormData();
for (var i in $scope.files) {
fd.append("uploadedFile", $scope.files[i]);
}
var imgDir = localStorage["img_dir"];
var uploadUrl = "ImageHandler.ashx?dir=" + imgDir;
$.ajax({ url: uploadUrl, dataType: 'text', cache: false, contentType: false, processData: false, data: fd, type: 'post', success: uploadComplete }).error(function() { alert("failed!") });
}