处理AJAX表单###

用Express处理AJAX表单非常简单;甚至可以使用相同的处理程序来处理AJAX请求和常规的浏览器回退。

  • HTML文件 (/views/newsletter.handlebars)
<div class="formContainer">
<form class="form-horizontal newsletterForm" role="form"
action="/process?form=newsletter" method="POST">
<input type="hidden" name="_csrf" value="{{csrf}}">
<div class="form-group">
<label for="fieldName" class="col-sm-2 control-label">Name</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="fieldName" name="name">
</div>
</div>
<div class="form-group">
<label for="fieldEmail" class="col-sm-2 control-label">Email</label>
<div class="col-sm-4">
<input type="email" class="form-control" required id="fieldName" name="email">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-4">
<button type="submit" class="btn btn-default">Register</button>
</div>
</div>
</form>
</div>
{{#section 'jquery'}}
<script>
$(document).ready(function(){
$('.newsletterForm').on('submit', function(evt){
evt.preventDefault();
var action = $(this).attr('action');
var $container = $(this).closest('.formContainer');
$.ajax({
url: action,
type: 'POST',
success: function(data){
if(data.success){
$container.html('<h2>Thank you!</h2>');
} else {
$container.html('There was a problem.');
}
},
error: function(){
$container.html('There was a problem.');
}
});
});
});
</script>
{{/section}}
  • 应用程序文件
app.post('/process', function(req, res){
if(req.xhr || req.accepts('json,html')==='json'){
// 如果发生错误,应该发送 { error: 'error description' }
res.send({ success: true });
} else {
// 如果发生错误,应该重定向到错误页面
res.redirect(303, '/thank-you');
}
});

Express提供了两个方便的属性:req.xhrreq.accepts。如果是AJAX请求(XHR是XML HTTP请求的简称,AJAX依赖于XHR),req.xhr值为truereq.accepts试图确定返回的最合适的响应类型。在此例中,req.accepts('json,html')询问最佳返回格式是JSON还是HTML:这可以根据Accepts HTTP头信息推断出来,它是浏览器提供的可读的、有序的响应类型列表。如果是一个AJAX请求,或者User-Agent明确要求JSON优先于HTML,那么就会返回合适的JSON数据;否则,返回一个重定向。

在这个函数里可以做任何处理:通常会将数据保存到数据库。如果出现问题,则返回一个err属性(而不是success)的JSON对象,或者重定向到一个错误页面(如果不是AJAX请求)。

在此例中,假设所有AJAX请求的是JSON数据,但是并没有要求AJAX通信必须使用JSON(事实上,“X”在AJAX中代表XML)。这个方法是jQuery友好的,因为通常jQuery假定所有数据都是JSON格式的。如果想让AJAX处理程序通用,或者知道AJAX请求使用JSON之外的东西,你应该根据Accepts头信息(可以根据req.accepts辅助方法轻松访问)返回一个适当的响应。如果响应完全基于Accepts头信息,你或许想看看c,这是一个可以根据客户端预期轻松做出适当响应的简便方法。如果这样做,必须保证用jQuery发起AJAX请求时设置dataTypeaccepts属性。

文件上传###

一般,文件上传可以使用Connect的内置中间件multipart来处理。但是,这个中间件已经从Connect中移除了,一旦Express更新了对Connect的依赖项,它也将从Express中消失,所以我强烈建议你不要使用这个中间件。

对于复合表单处理,目前有两种流行而健壮的选择:BusboyFormidable。Formidable要稍微简单一些,因为它有一个方便的回调方法,能够提供包含字段和文件信息的对象。对于Busboy而言,必须对每一个字段和文件事件进行监听。

  • (views/contest/vacation-photo.handlebars)
<form class="form-horizontal" role="form"
enctype="multipart/form-data" method="POST"
action="/contest/vacation-photo/{year}/{month}">
<div class="form-group">
<label for="fieldName" class="col-sm-2 control-label">Name</label>
<div class="col-sm-4">
<input type="text" class="form-control"
id="fieldName" name="name">
</div>
</div>
<div class="form-group">
<label for="fieldEmail" class="col-sm-2 control-label">Email</label>
<div class="col-sm-4">
<input type="email" class="form-control" required
id="fieldName" name="email">
</div>
</div>
<div class="form-group">
<label for="fieldPhoto" class="col-sm-2 control-label">Vacation photo
</label>
<div class="col-sm-4">
<input type="file" class="form-control" required accept="image/*" id="fieldPhoto" name="photo">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-4">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>

注意,我们必须指定enctype="multipart/form-data"来启用文件上传。我们也可以通过accept属性来限制上传文件的类型(这是可选的)。

  • 安装Formidable(npm install --save formidable)并创建一下路由处理程序:
var formidable = require('formidable');

app.get('/contest/vacation-photo',function(req,res){
var now = new Date();
res.render('contest/vacation-photo',{
year: now.getFullYear(),month: now.getMont()
});
}); app.post('/contest/vacation-photo/:year/:month', function(req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files){
if(err) return res.redirect(303, '/error');
console.log('received fields:');
console.log(fields);
console.log('received files:');
console.log(files);
res.redirect(303, '/thank-you');
});
});

(year和month被指定为路由参数)。继续运行,检查控制台日志。你会发现表单字段如你预期的那样:是一个有字段名称属性的对象。文件对象包含更多的数据,但这是相对简单的。对于每一个上传的文件,你会看到属性有文件大小、上传路径(通常是在临时目录中的一个随机名字),还有用户上传此文件的原始名字(文件名,而不是整个路径,出于安全隐私考虑)。

接下来如何处理这个文件就取决于你了:可以将它保存到数据库,将其复制到更持久的位置,或者上传到云端文件存储系统。记住,如果你基于本地存储保存文件,应用程序不能很好地扩展,基于云端存储是一个更好的选择。

jQuery文件上传###

如果想为用户提供真正别出心裁的文件上传,可拖拽,可以看到上传文件缩略图,并查看进度条,那推荐 Sebastian Tschan的jQuery File Upload

要显示文件缩略图,jquery-file-upload-middleware使用[ImageMagick](http://www.imagemagick.org

在Ubuntu和Debian系统中,可以使用apt-get install imagemagick安装ImageMagick;在OS X中,你可以使用brew install imagemagick来安装。对于其他操作系统,请参考[ImageMagick文档](http://www.imagemagick.org/script/binary-releases.php)。

  • 首先,安装jquery-file-upload-middleware包(npm install --save jquery-file-upload-middleware),然后在你的应用文件中添加以下代码:
var jqupload = require('jquery-file-upload-middleware');

app.use('/upload', function(req, res, next){
var now = Date.now();
jqupload.fileHandler({
uploadDir: function(){
return __dirname + '/public/uploads/' + now;
},
uploadUrl: function(){
return '/uploads/' + now;
},
})(req, res, next);
});

除非为所有访问者提供一个共用的文件上传区域,否则可能要将上传文件区分开来。简单的方法是创建一个时间戳目录来存储文件。更实际的做法是使用用户ID或其他唯一ID来创建子目录。

请注意,我们将jQuery File Upload中间件挂载在/upload前缀上。你可以在这里使用任何前缀,但是确保该前缀不用于其他路由或中间件,不然会干扰文件上传操作。

  • 接下来是文件上传的视图,你可以直接复制演示上传代码:你可以在project's GitHub页面上传最新项目包。

如果你只想要一个可构建的最小示例,需要如下脚本:

js/vendor/jquery.ui.widget.jsjs/jquery.iframe-transport.js和js/jquery.fileupload.js。

在这个最小实现中,我们将<input type="file">元素放在<span>中,还有一个<div>用来列出所有已上传文件:

<span class="btn btn-default btn-file">
Upload
<input type="file" class="form-control" required accept="image/*"
id="fieldPhoto" data-url="/upload" multiple name="photo">
</span>
<div id="uploads"></div>
  • 然后我们加上jQuery File Upload:
{{#section 'jquery'}}
<script src="/vendor/jqfu/js/vendor/jquery.ui.widget.js"></script>
<script src="/vendor/jqfu/js/jquery.iframe-transport.js"></script>
<script src="/vendor/jqfu/js/jquery.fileupload.js"></script>
<script>
$(document).ready(function(){ $('#fieldPhoto').fileupload({
dataType: 'json',
done: function(e, data){
$.each(data.result.files, function(index, file){
$('#fileUploads').append($('<div class="upload">' +
'<span class="glyphicon glyphicon-ok"></span>' +
'&nbsp;' + file.originalName + '</div>'));
});
}
});
});
</script>
{{/section}}
  • 为上传按钮添加CSS动态样式:
.btn-file {
position: relative;
overflow: hidden;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 999px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: white;
cursor: inherit;
display: block;
}

注意,<input>标签里的data-url属性必须和用于中间件的路由前缀相匹配。在这个简单示例中,当一个文件上传完成后,一个<div class="upload">元素会附加到之前的<div id="uploads">下面。这个列表只显示文件名和大小,不提供删除、运行或者缩略图功能。但这是一个好的开始。定制jQuery File Upload演示程序会让人望而生畏,如果你的视角完全不同,从最小程序开始逐渐向上构建,而不是从演示和定制开始,可能会更简单。不管怎样,你会在jQuery File Upload文档网页找到你想要的资源。

express-11 表单处理(2)的更多相关文章

  1. ddms(基于 Express 的表单管理系统)源码学习

    ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下. 数据层封装 模块只对外暴露mod ...

  2. iOS开发笔记11:表单键盘遮挡、浮点数价格格式化显示、省市区选择器、View Debugging

    1.表单键盘遮挡 应用场景为一个collectionView上有多个textfield.textView供用户填写信息. 之前输入项较少时,采取的方法比较粗暴,didSelectItemAtIndex ...

  3. Express ~ 获取表单 get 和 post 提交方式传送参数的对比

      一,获取 get 提交的参数   var id = req.query.id || ''   二,获取 post 提交的参数 var name = req.body.name || ''

  4. html_表单

    一.表单框架简介 表单是提供让读者在网页上输入,勾选和选取数据,以便提交给服务器数据库的工具.(用于将信息提交给服务器) <form>...</form>标记 作用:用于创建一 ...

  5. from表单实现无跳转上传文件,接收页面后台数据。

    本文基于我刚写的http://www.cnblogs.com/iwang5566/p/6287529.html进行了简单的扩展,实现页面无跳转表单数据提交,并接收后台返回的数据. 下载好,上一篇文章d ...

  6. js02--对象、函数、switch、for、异常、表单验证

    现在我们接着来继续学习有关js的一些基础. 1.undefined与null    undefined:当变量声明但尚未赋值时,它的类型就是undefined    null:表示一个不存在的对象,它 ...

  7. bootstrap基础学习【表单含按钮】(二)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. HTML表单学习

    HTML表单学习 前言 HTML基础学习会由HTML基础标签学习.HTML表单学习和一张思维导图总结HTML基础三篇文章构成,文章中博主会提取出重点常用的知识和经常出现的bug,提高学习的效率,后续会 ...

  9. SpringMVC学习系列(11) 之 表单标签

    本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图上展示WebModel中的数据更加轻松. 一.首先我们先做一个简单了例子来对Spring MV ...

随机推荐

  1. Android实现Banner界面广告图片循环轮播(包括实现手动滑动循环)

    前言:经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环.本以为单纯的ViewPager就可以实现这些功能.但是蛋疼的事情来了,ViewPager并不支持循环翻页.所以 ...

  2. 【leetcode】Excel Sheet Column Title & Excel Sheet Column Number (easy)

    Given a positive integer, return its corresponding column title as appear in an Excel sheet. For exa ...

  3. .NET微信公众号开发-5.0微信支付

    一.前言 在开始做这个功能之前,我们要做的第一件事情就是思考,如何做这个微信支付,从哪里开始,从哪里入手,官方的sdk说明什么的,有没有什么官方的demo,还有就是老板给我的一些资料齐全不,那些要申请 ...

  4. Cannot change version of project facet Dynamic Web Module to 3.0

    背景描述: 最近在开发项目时,老是报错说:Project is not Dynamic Web Module 3.0.右击项目选择属性进行修改时出现以下错误: 这让我很是恼火,后来终于找到了万能的解决 ...

  5. ios cell展示可滑动的图片

    需求: 点击cell上的图片.图片以原图显示出来,可以放大或缩小.再次点击图片移除图片显示原来界面.(和QQ空间看图片类似) 点击图片实现效果: 1. 自定义一个 UITableView (KDIma ...

  6. QT_SVG格式图片浏览器_源代码下载_详细注释

    源代码链接: http://pan.baidu.com/s/1pKA5Vcv 密码: ib2x 注:SVG格式图片特点: 1. 文件小 2. 图像中文字独立于图像, 可以编辑,可搜索. 3.没有字体限 ...

  7. No space left on device 解决Linux系统磁盘空间满的办法

    最近Linux电脑在执行mvn时候总是报错: No space left on device   原因是磁盘空间满了,我马上加了20G的硬盘容量,但是还是报错,上网查了一下,发现了解决方法,我用了其中 ...

  8. 高效使用你的Xcode

    (via:VongLo's Dev Space  原文:Supercharging Your Xcode Efficiency)   好莱坞电影里经常看到黑客们手指在键盘上飞速跳跃,同时终端上的代码也 ...

  9. 求sqrt()底层效率问题(二分/牛顿迭代)

    偶然看见一段求根的神代码,于是就有了这篇博客: 对于求根问题,通常我们可以调用sqrt库函数,不过知其然需知其所以然,我们看一下求根的方法: 比较简单方法就是二分咯: 代码: #include< ...

  10. 从xml中构建sqlSessionFactory

    String resource = "org/mybatis/example/Configuration.xml"; Reader reader = Resources.getRe ...