详细分析使用AngularJS编程中提交表单的方式


Posted in Javascript onJune 19, 2015

在AngularJS出现之前,很多开发者就面对了表单提交这一问题。由于提交表单的方式繁杂而不同,很容易令人疯掉……然而现在看来,依然会让人疯掉。

今天,我们会看一下过去使用PHP方式提交的表单,现在如何将其转换为使用Angular提交。使用Angular来处理表单,对我而言,是一个“啊哈”时刻(译者:表示了解或发现某事物的喜悦)。即使它甚至都没有涉及多少Angular表层的东西,但是它却帮助用户看到表单提交之后的潜力,并且理解两种数据绑定方式。

我们会使用jQuery平台来进行这个处理过程。所以所要做的工作首先使用javascript。我们会提交表单,展示错误信息,添加错误类,并且在javascript中显示和隐藏信息。

之后,我们会使用Angular。在使用之前,我们要做大部分所需的工作,并且我们之前所做的很多工作会非常容易。让我们开始吧。

简单的表单

我们会关注两种提交表单的方式:

  •     旧方法:jQuery和PHP提交表单
  •     新方法:AngularJS和PHP提交表单

首先看一下我们的表单,超级简单:

详细分析使用AngularJS编程中提交表单的方式

形式要求

  •     实现页面无刷新表单处理
  •     输入姓名和超级英雄别名
  •     如果有错误,显示错误提示
  •     如果输入有误,将输入变成红色
  •     如果所有内容ok,显示成功提示

文档结构

在我们的展示中,仅需两个文件

  •     index.html
  •     process.php

 
表单处理

让我们新建一个PHP来处理表单。该页面非常小并且使用POST方式提交数据。

处理表单:这对我们来说并不是那么重要的。你可以使用其他你喜欢的语言来处理你的表单。
 

// process.php
 
<?php
 
$errors   = array();  // array to hold validation errors
$data    = array();   // array to pass back data
 
// validate the variables ======================================================
 if (empty($_POST['name']))
  $errors['name'] = 'Name is required.';
 
 if (empty($_POST['superheroAlias']))
  $errors['superheroAlias'] = 'Superhero alias is required.';
 
// return a response ===========================================================
 
 // response if there are errors
 if ( ! empty($errors)) {
 
  // if there are items in our errors array, return those errors
  $data['success'] = false;
  $data['errors'] = $errors;
 } else {
 
  // if there are no errors, return a message
  $data['success'] = true;
  $data['message'] = 'Success!';
 }
 
 // return all our data to an AJAX call
 echo json_encode($data);
这是一个非常简单的表单处理脚本。我们仅检查数据是否存在,如果存在,则不做任何处理和操做;如果不存在,则需要向$errors数组中添加一条信息。

为了返回我们的数据用于AJAX调用,我们需要使用echo和json_encode。这就是我们PHP表单处理所有需要做的操作。使用普通的jQuery AJAX或者Angular处理表单也是这样的。
 展示表单

让我们创建一个HTML来展示我们的表单

<!-- index.html -->
 
<!doctype html>
<html>
<head>
 <title>Angular Forms</title>
 
 <!-- LOAD BOOTSTRAP CSS -->
 <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
 
 <!-- LOAD JQUERY -->
  <!-- when building an angular app, you generally DO NOT want to use jquery -->
  <!-- we are breaking this rule here because jQuery's $.param will help us send data to our PHP script so that PHP can recognize it -->
  <!-- this is jQuery's only use. avoid it in Angular apps and if anyone has tips on how to send data to a PHP script w/o jQuery, please state it in the comments -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
 
 <!-- PROCESS FORM WITH AJAX (OLD) -->
 <script>
  <!-- WE WILL PROCESS OUR FORM HERE -->
 </script>
</head>
<body>
<div class="container">
<div class="col-md-6 col-md-offset-3">
 
 <!-- PAGE TITLE -->
 <div class="page-header">
  <h1><span class="glyphicon glyphicon-tower"></span> Submitting Forms with Angular</h1>
 </div>
 
 <!-- SHOW ERROR/SUCCESS MESSAGES -->
 <div id="messages"></div>
 
 <!-- FORM -->
 <form>
  <!-- NAME -->
  <div id="name-group" class="form-group">
   <label>Name</label>
   <input type="text" name="name" class="form-control" placeholder="Bruce Wayne">
   <span class="help-block"></span>
  </div>
 
  <!-- SUPERHERO NAME -->
  <div id="superhero-group" class="form-group">
   <label>Superhero Alias</label>
   <input type="text" name="superheroAlias" class="form-control" placeholder="Caped Crusader">
   <span class="help-block"></span>
  </div>
 
  <!-- SUBMIT BUTTON -->
  <button type="submit" class="btn btn-success btn-lg btn-block">
   <span class="glyphicon glyphicon-flash"></span> Submit!
  </button>
 </form>
 
</div>
</div>
</body>
</html>

现在,我们有了表单。我们另外还使用了Bootstrap来使表单看起来不是那么丑。使用Bootstrap语法规则,每个input下含有一个spot来展示我们文本的错误信息。

详细分析使用AngularJS编程中提交表单的方式

使用jQuery提交表单

现在,让我们来使用jQuery处理表单提交。我会将所有的代码添加到空的<script>标签中
 

<!-- index.html -->
 
...
 
 <!-- PROCESS FORM WITH AJAX (OLD) -->
 <script>
  $(document).ready(function() {
 
   // process the form
   $('form').submit(function(event) {
 
    // remove the past errors
    $('#name-group').removeClass('has-error');
    $('#name-group .help-block').empty();
    $('#superhero-group').removeClass('has-error');
    $('#superhero-group .help-block').empty();
 
    // remove success messages
    $('#messages').removeClass('alert alert-success').empty();
 
    // get the form data
    var formData = {
     'name'     : $('input[name=name]').val(),
     'superheroAlias'  : $('input[name=superheroAlias]').val()
    };
 
    // process the form
    $.ajax({
     type   : 'POST',
     url   : 'process.php',
     data   : formData,
     dataType  : 'json',
     success  : function(data) {
 
      // log data to the console so we can see
      console.log(data);
 
      // if validation fails
      // add the error class to show a red input
      // add the error message to the help block under the input
      if ( ! data.success) {
 
       if (data.errors.name) {
        $('#name-group').addClass('has-error');
        $('#name-group .help-block').html(data.errors.name);
       }
 
       if (data.errors.superheroAlias) {
        $('#superhero-group').addClass('has-error');
        $('#superhero-group .help-block').html(data.errors.superheroAlias);
       }
 
      } else {
 
       // if validation is good add success message
       $('#messages').addClass('alert alert-success').append('<p>' + data.message + '</p>');
      }
     }
    });
 
    // stop the form from submitting and refreshing
    event.preventDefault();
   });
 
  });
 </script>
 
...

这里处理表单有不少的代码。我们有获取表单中变量的代码,有使用AJAX将数据发送至我们的表单的代码,有检查是否有错和显示成功提示的代码。除此之外,我们希望每次表单提交之后,过去的错误信息都会被清除。确实是不少代码。

现在,如果表单中含有错误,则:

详细分析使用AngularJS编程中提交表单的方式

如果提交成功:

详细分析使用AngularJS编程中提交表单的方式

现在,让我们看使用Angular来提交相同的表单。记住,我们不需要更改任何关于我们的PHP如何处理表单的内容,我们的应用依然会具备相同的功能(在同一个地方展示错误和成功信息)。

使用Angular提交表单

我们准备在之前使用的<script>标签中设置我们的Angular应用。所以删除里面的内容,我们就可以开始了。
设置一个Angular应用

步骤为:

    1. 加载Angular

    2. 设置module

    3. 这是controller

    4. 将module和controller应用于HTML

    5. 设置双向变量绑定

    6. 这是错误和信息

看起来好像是很多内容,但是最终,我们会用非常少的代码,并且看起来会非常简洁。另外,创建带有更多输入更大的表单,也会更容易。

Angular 组件和控制器

首先,加载Angular并且新建组件和控制器
 

<!-- index.html -->
 
...
 
 <!-- LOAD JQUERY -->
 <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
 <!-- LOAD ANGULAR -->
 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
 
 <!-- PROCESS FORM WITH AJAX (NEW) -->
 <script>
 
  // define angular module/app
  var formApp = angular.module('formApp', []);
 
  // create angular controller and pass in $scope and $http
  function formController($scope, $http) {
 
  }
 
 </script>
</head>
 
<!-- apply the module and controller to our body so angular is applied to that -->
<body ng-app="formApp" ng-controller="formController">
 
...

现在,我们有了Angular应用的基础。我们已经加载了Angular,创建了组件模块和控制器,并且将其应用于我们的网站。

接下来,我将展示双向绑定是如何工作的。

双向数据绑定

这是Angular的核心思想之一,也是功能最强大的内容之一。在Angular文档中,我们看到:“在Angular网页应用中的数据绑定,是模型和视图层之间的数据自动同步。”这意味着,我们需要在表单中抓取数据,使用$('input[name=name]').val()并不是必需的。

我们在Angular中将数据和变量绑定在一起,无论是javascript也好,view也罢,只要有改变,两者皆变。

为了演示数据绑定,我们需要获取表单的input来自动填充变量formData。让我们回到应用于页面的Angular控制器中。我们在过一下$scope和$http。

$scope:控制器和视图层之间的粘合剂。基本上,变量使用$scope从我们的控制器和视图层之间传递和往来。具体详细的定义,请参见文档。

$http:Angular服务来帮助我们处理POST请求。更多信息,请参见文档。

使用数据绑定获取变量

好了,闲话少说。我们将这些讨论应用到表单中去。方法比上面讨论的要简单。我们想Angular控制器和视图中分别添加一行。
 

<!-- index.html -->
 
...
 
 <!-- PROCESS FORM WITH AJAX (NEW) -->
 <script>
 
  // define angular module/app
  var formApp = angular.module('formApp', []);
 
  // create angular controller and pass in $scope and $http
  function formController($scope, $http) {
 
   // create a blank object to hold our form information
   // $scope will allow this to pass between controller and view
   $scope.formData = {};
 
  }
 
...

现在,我们已经建立了一个formData对象。让我们用表单数据来填充它。在显示调用每个输入和获得val()之前,我们用ng-model绑定一个特殊的输入到变量。
 

<!-- index.html -->
 
...
 
 <!-- FORM -->
 <form>
  <!-- NAME -->
  <div id="name-group" class="form-group">
   <label>Name</label>
   <input type="text" name="name" class="form-control" placeholder="Bruce Wayne" ng-model="formData.name">
   <span class="help-block"></span>
  </div>
 
  <!-- SUPERHERO NAME -->
  <div id="superhero-group" class="form-group">
   <label>Superhero Alias</label>
   <input type="text" name="superheroAlias" class="form-control" placeholder="Caped Crusader" ng-model="formData.superheroAlias">
   <span class="help-block"></span>
  </div>
 
  <!-- SUBMIT BUTTON -->
  <button type="submit" class="btn btn-success btn-lg btn-block">
   <span class="glyphicon glyphicon-flash"></span> Submit!
  </button>
 </form>
 
 <!-- SHOW DATA FROM INPUTS AS THEY ARE BEING TYPED -->
 <pre>
  {{ formData }}
 </pre>
 
...

现在,既然Angular已经将每个输入绑到了formData。 当你输入每个输入框,你可以看到formData对象被填充了!有没有很酷!

你不必在view中使用$scope。一切被认为是嵌入到$scope中的。
 
处理表单

在我们的旧表单中,我们使用jQuery提交表单,像这样$('form').submit()。现在我们使用Angular称作ng-submit的特性。要想完成这个,我们需要添加一个控制器函数来处理表单,然后告诉我们form使用这个控制器函数:
 

<!-- index.html -->
 
...
 
 <!-- PROCESS FORM WITH AJAX (NEW) -->
 <script>
 
  // define angular module/app
  var formApp = angular.module('formApp', []);
 
  // create angular controller and pass in $scope and $http
  function formController($scope, $http) {
 
   // create a blank object to hold our form information
   // $scope will allow this to pass between controller and view
   $scope.formData = {};
 
   // process the form
   $scope.processForm = function() {
 
   };
 
  }
 
...
 
 <!-- FORM -->
 <form ng-submit="processForm()">
 
...

现在我们的form知道提交时使用控制器函数了。既然已经到位了,然我们用$http来处理表单吧。

处理表单的语法看起来跟原始方式很像。好处是我们不需要手动抓取表单数据,或者注入,隐藏,添加类显示错误或成功信息。
 

<!-- index.html -->
 
...
 
// process the form
$scope.processForm = function() {
 $http({
  method : 'POST',
  url  : 'process.php',
  data : $.param($scope.formData), // pass in data as strings
  headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
 })
  .success(function(data) {
   console.log(data);
 
   if (!data.success) {
    // if not successful, bind errors to error variables
    $scope.errorName = data.errors.name;
    $scope.errorSuperhero = data.errors.superheroAlias;
   } else {
    // if successful, bind success message to message
    $scope.message = data.message;
   }
  });
};
 
...

这就是我们的表单!没有添加或移除类。我们需要每次提交表单时都清楚错误。我们只需绑定变量和需要用到的视图。这非常棒,因为处理器用来处理数据,而视图用来显示数据.

jQuery POST vs Angular POST

有时能看到用POST方式提交在服务器中看不到数据,这是因为jQuery和Angular的序列化和发送数据的方式不同。这归结于你所使用的服务器语言和它理解Angular提交的数据的能力。

上面的代码是应用于PHP服务器的,jQuery对于$.param函数则是必需的。虽然实现上文中提到的内容有非常多不使用jQuery的方法,但在本实例中,使用jQuery的唯一原因就是,它更简单。

下面简洁的语法将会基于你服务器端语言来工作。

简洁语法

这个例子是以字符串的方式发送数据,并且发送你的头信息。如果你不需要这些,并且希望Angular 的$http POST尽可能的简洁,我们可以使用简写方法:
 

...
 $http.post('process.php', $scope.formData)
  .success(function(data) {
   ...
  });
...

绝对更简洁更容易记住方法。

$http 内部控制器: 理想的,你可以将$http请求从controller移除到 service.这只是为了演示目的,我们将会尽快在service上进行讨论.

在视图中显示错误和信息

我们将使用指令ng-show和ng-class来处理我们的视图,Angular双方括号允许我们将变量放置在我们需要的地方。

  • ng-show: 根据变量值是否存在来显示或隐藏元素. 文档
  • ng-class: 根据变量值是否存在(或一些其他表达式)来添加或移除类. 文档
<!-- index.html -->
 
...
 
 <!-- SHOW ERROR/SUCCESS MESSAGES -->
 <div id="messages" ng-show="message">{{ message }}</div>
 
 <!-- FORM -->
 <form>
  <!-- NAME -->
  <div id="name-group" class="form-group" ng-class="{ 'has-error' : errorName }">
   <label>Name</label>
   <input type="text" name="name" class="form-control" placeholder="Bruce Wayne">
   <span class="help-block" ng-show="errorName">{{ errorName }}</span>
  </div>
 
  <!-- SUPERHERO NAME -->
  <div id="superhero-group" class="form-group" ng-class="{ 'has-error' : errorSuperhero }">
   <label>Superhero Alias</label>
   <input type="text" name="superheroAlias" class="form-control" placeholder="Caped Crusader">
   <span class="help-block" ng-show="errorSuperhero">{{ errorSuperhero }}</span>
  </div>
 
...

我们的表单完成了!通过强大的Angular,我们可以将这些愚蠢的显示/隐藏的js代码逻辑从视图中移走 了。现在我们的js文件只用来处理数据,并且视图可以做它自己的事情了。

我们的类和错误/成功等提示信息将在可获取时显示而不可获取时隐藏。当我们无须再像使用老的javascript那样担心是否已经考虑全面,这变得更加容易。你也无须再担心是否记得隐藏每处form提交时的那些错误信息。

Angular表单验证 获取更多表单验证的信息,请研读我们另一文章:AngularJS Form Validation。
结束语

现在我们已把美观的表单全部转变为Angular的了。我们共同学习了许多概念,希望你与它们接触更多,它们也将更易用。

回顾:

  •     创建一个Angular module
  •     创建一个Angular controller
  •     双向数据绑定
  •     ng-model绑定inputs
  •     ng-click提交表单
  •     使用双向数据绑定展示表单错误
  •     展示一个基于是否变量存在的div
  •     添加一个基于是否变量存在的类

这些Angular技术将在更庞大的应用中使用,你可以用它们创建许多好东西。祝Angular之途愉快,敬请期待更多深入的文章。同时,你也可以通过深入了解其指南,服务和厂商等来继续学习Angular。

Javascript 相关文章推荐
Javascript实例教程(19) 使用HoTMetal(5)
Dec 23 Javascript
Javascript中的常见排序算法
Mar 27 Javascript
JQuery触发事件例如click
Sep 11 Javascript
javascript计算星座属相(十二生肖属相)示例代码
Jan 09 Javascript
js实现的GridView即表头固定表体有滚动条且可滚动
Feb 19 Javascript
JavaScript判断textarea值是否为空并给出相应提示
Sep 04 Javascript
Javascript removeChild()删除节点及删除子节点的方法
Dec 27 Javascript
JQuery 封装 Ajax 常用方法(推荐)
May 21 jQuery
微信小程序分享功能onShareAppMessage(options)用法分析
Apr 24 Javascript
taro小程序添加骨架屏的实现代码
Nov 15 Javascript
解决vue-photo-preview 异步图片放大失效的问题
Jul 29 Javascript
JavaScript ES 模块的使用
Nov 12 Javascript
让JavaScript中setTimeout支持链式操作的方法
Jun 19 #Javascript
js控制文本框输入的字符类型方法汇总
Jun 19 #Javascript
详细解读AngularJS中的表单验证编程
Jun 19 #Javascript
JavaScript中模拟实现jsonp
Jun 19 #Javascript
基于jQuery+Cookie实现的防止刷新的在线考试倒计时
Jun 19 #Javascript
MVVM模式中ViewModel和View、Model有什么区别?
Jun 19 #Javascript
JavaScript中数据结构与算法(五):经典KMP算法
Jun 19 #Javascript
You might like
一个可查询所有表的“通用”查询分页类
2006/10/09 PHP
PHP编程之设置apache虚拟目录
2016/07/08 PHP
tp5(thinkPHP5框架)使用DB实现批量删除功能示例
2019/05/28 PHP
jQuery实现id模糊查询的小例子
2013/03/19 Javascript
点击隐藏页面左栏或右栏实现js代码
2013/04/01 Javascript
js中关于一个分号的崩溃示例
2013/11/11 Javascript
JSON.stringify转换JSON时日期时间不准确的解决方法
2014/08/08 Javascript
JavaScript常用基础知识强化学习
2015/12/09 Javascript
JavaScript学习笔记整理之引用类型
2016/01/22 Javascript
Vue.js学习笔记之 helloworld
2016/08/14 Javascript
关于JavaScript和jQuery的类型判断详解
2016/10/08 Javascript
基于javascript实现的购物商城商品倒计时实例
2016/12/11 Javascript
NodeJS学习笔记之Module的简介
2017/03/24 NodeJs
使用webpack打包koa2 框架app
2018/02/02 Javascript
jsonp跨域获取百度联想词的方法分析
2019/05/13 Javascript
JavaScript常用内置对象用法分析
2019/07/09 Javascript
vue-mugen-scroll组件实现pc端滚动刷新
2019/08/16 Javascript
node.js中Buffer缓冲器的原理与使用方法分析
2019/11/23 Javascript
微信小程序button标签open-type属性原理解析
2020/01/21 Javascript
详解ES6 CLASS在微信小程序中的应用实例
2020/04/24 Javascript
Electron实现应用打包、自动升级过程解析
2020/07/07 Javascript
Python内置函数—vars的具体使用方法
2017/12/04 Python
python处理csv数据动态显示曲线实例代码
2018/01/23 Python
Python基于分析Ajax请求实现抓取今日头条街拍图集功能示例
2018/07/19 Python
python全栈知识点总结
2019/07/01 Python
python 正则表达式贪婪模式与非贪婪模式原理、用法实例分析
2019/10/14 Python
Python实现AES加密,解密的两种方法
2020/10/03 Python
python tqdm实现进度条的示例代码
2020/11/10 Python
python使用matplotlib的savefig保存时图片保存不完整的问题
2021/01/08 Python
HTML页面中添加Canvas标签示例
2015/01/01 HTML / CSS
95%的面试官都会问到的50道Java线程题,附答案
2012/08/03 面试题
2014高考励志标语
2014/06/05 职场文书
党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
Java使用Unsafe类的示例详解
2021/09/25 Java/Android
MySQL数据库索引的最左匹配原则
2021/11/20 MySQL
MySQL分区以及建索引的方法总结
2022/04/13 MySQL