使用PHP和AJAX在Bootstrap联系表单上显示错误消息

时间:2018-05-29 16:20:36

标签: javascript php ajax forms email-validation

继承Contact form page我遇到显示错误消息的问题。当我提交表单时,它会重定向到空白页面(并且能够从表单接收电子邮件),而不是在表单顶部显示消息。

contact.php空白页面上,看起来AJAX没有做任何事情来显示messages类中的消息 -

// if requested by AJAX request return JSON response
if (empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    $encoded = json_encode($responseArray);
    header('Content-Type: application/json');
    return $encoded;
}
// else just display the message
else {
    return $responseArray['message'];
}

表格 -

<form id="contact-form" method="post" action="contact.php" role="form">
<div class="messages"></div> <--------- messages to display
...
</form>

配置contact.php -

<?php
// an email address that will be in the From field of the email.
$from = 'Contact form';

// an email address that will receive the email with the output of the form
$sendTo = $_POST['email'];

// subject of the email
$subject = 'New message from contact form';

// form field names and their translations.
// array variable name => Text to appear in the email
$fields = array('name' => 'Name', 'surname' => 'Surname', 'phone' => 
'Phone', 'email' => 'Email', 'message' => 'Message'); 

// message that will be displayed when everything is OK :)
$okMessage = 'Contact form successfully submitted. Thank you, I will get back to you soon!';

// If something goes wrong, we will display this message.
$errorMessage = 'There was an error while submitting the form. Please try again later';

// if you are not debugging and don't need error reporting, turn this off by 
error_reporting(0);
error_reporting(E_ALL & ~E_NOTICE);

try
{

if(count($_POST) == 0) throw new \Exception('Form is empty');

$emailText = "You have a new message from your contact 
form\n=============================\n";

foreach ($_POST as $key => $value) {
    // If the field exists in the $fields array, include it in the email 
    if (isset($fields[$key])) {
        $emailText .= "$fields[$key]: $value\n";
    }
}

// All the neccessary headers for the email.
$headers = array('Content-Type: text/plain; charset="UTF-8";',
    'From: ' . $from,
    'Reply-To: ' . $from,
    'Return-Path: ' . $from,
);

// Send email
mail($sendTo, $subject, $emailText, implode("\n", $headers));

$responseArray = array('type' => 'success', 'message' => $okMessage);
}
catch (\Exception $e)
{
$responseArray = array('type' => 'danger', 'message' => $errorMessage);
}


// if requested by AJAX request return JSON response
if (empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&  strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$encoded = json_encode($responseArray);

header('Content-Type: application/json');

return $encoded;
}
// else just display the message
else {
return $responseArray['message'];
}

AJAX - contact.js

$(function () {

$('#contact-form').validator();

// when the form is submitted
$('#contact-form').on('submit', function (e) {

    // if the validator does not prevent form submit
    if (e.isDefaultPrevented()) {
        var url = "contact.php";

        // POST values in the background the the script URL
        $.ajax({
            type: "POST",
            url: url,
            data: $(this).serialize(),
            success: function (data)
            {
                // data = JSON object that contact.php returns

                // we recieve the type of the message: success x danger and apply it to the 
                var messageAlert = 'alert-' + data.type;
                var messageText = data.message;

                // let's compose Bootstrap alert box HTML
                var alertBox = '<div class="alert ' + messageAlert + ' alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>' + messageText + '</div>';

                // If we have messageAlert and messageText
                if (messageAlert && messageText) {
                    // inject the alert to .messages div in our form
                    $('#contact-form').find('.messages').html(alertBox);
                    // empty the form
                    $('#contact-form')[0].reset();
                }
            }
        });
    }
});
});

validator.js

+function ($) {
'use strict';

// VALIDATOR CLASS DEFINITION
// ==========================

function getValue($el) {
return $el.is('[type="checkbox"]') ? $el.prop('checked'):
       $el.is('[type="radio"]')    ? !!$('[name="' + $el.attr('name') + 
'"]:checked').length :
                                     $el.val()
}

var Validator = function (element, options) {
this.options    = options
this.validators = $.extend({}, Validator.VALIDATORS, options.custom)
this.$element   = $(element)
this.$btn       = $('button[type="submit"], input[type="submit"]')
                    .filter('[form="' + this.$element.attr('id') + '"]')
                    .add(this.$element.find('input[type="submit"], button[type="submit"]'))

this.update()

this.$element.on('input.bs.validator change.bs.validator 
focusout.bs.validator', $.proxy(this.onInput, this))
this.$element.on('submit.bs.validator', $.proxy(this.onSubmit, this))
this.$element.on('reset.bs.validator', $.proxy(this.reset, this))

this.$element.find('[data-match]').each(function () {
  var $this  = $(this)
  var target = $this.data('match')

  $(target).on('input.bs.validator', function (e) {
    getValue($this) && $this.trigger('input.bs.validator')
  })
   })

this.$inputs.filter(function () { return getValue($(this)) 
}).trigger('focusout')

this.$element.attr('novalidate', true) // disable automatic native validation
this.toggleSubmit()
    }

 Validator.VERSION = '0.11.5'

 Validator.INPUT_SELECTOR = ':input:not([type="hidden"], [type="submit"], [type="reset"], button)'

 Validator.FOCUS_OFFSET = 20

 Validator.DEFAULTS = {
delay: 500,
html: false,
disable: true,
focus: true,
custom: {},
errors: {
  match: 'Does not match',
  minlength: 'Not long enough'
 },
 feedback: {
  success: 'glyphicon-ok',
  error: 'glyphicon-remove'
 }
 }

 Validator.VALIDATORS = {
 'native': function ($el) {
  var el = $el[0]
  if (el.checkValidity) {
    return !el.checkValidity() && !el.validity.valid && (el.validationMessage || "error!")
  }
  },
'match': function ($el) {
  var target = $el.data('match')
  return $el.val() !== $(target).val() && Validator.DEFAULTS.errors.match
},
'minlength': function ($el) {
  var minlength = $el.data('minlength')
  return $el.val().length < minlength && Validator.DEFAULTS.errors.minlength
  }
 }

 Validator.prototype.update = function () {
 this.$inputs = this.$element.find(Validator.INPUT_SELECTOR)
  .add(this.$element.find('[data-validate="true"]'))
  .not(this.$element.find('[data-validate="false"]'))

 return this
 }

 Validator.prototype.onInput = function (e) {
 var self        = this
 var $el         = $(e.target)
 var deferErrors = e.type !== 'focusout'

 if (!this.$inputs.is($el)) return

 this.validateInput($el, deferErrors).done(function () {
  self.toggleSubmit()
 })
 }

 Validator.prototype.validateInput = function ($el, deferErrors) {
 var value      = getValue($el)
 var prevErrors = $el.data('bs.validator.errors')
 var errors

 if ($el.is('[type="radio"]')) $el = this.$element.find('input[name="' + $el.attr('name') + '"]')

 var e = $.Event('validate.bs.validator', {relatedTarget: $el[0]})
 this.$element.trigger(e)
 if (e.isDefaultPrevented()) return

 var self = this

 return this.runValidators($el).done(function (errors) {
  $el.data('bs.validator.errors', errors)

  errors.length
    ? deferErrors ? self.defer($el, self.showErrors) : self.showErrors($el)
    : self.clearErrors($el)

  if (!prevErrors || errors.toString() !== prevErrors.toString()) {
    e = errors.length
      ? $.Event('invalid.bs.validator', {relatedTarget: $el[0], detail: errors})
      : $.Event('valid.bs.validator', {relatedTarget: $el[0], detail: prevErrors})

    self.$element.trigger(e)
  }

  self.toggleSubmit()

  self.$element.trigger($.Event('validated.bs.validator', {relatedTarget: $el[0]}))
  })
 }


 Validator.prototype.runValidators = function ($el) {
   var errors   = []
   var deferred = $.Deferred()

   $el.data('bs.validator.deferred') && 
   $el.data('bs.validator.deferred').reject()
   $el.data('bs.validator.deferred', deferred)

function getValidatorSpecificError(key) {
  return $el.data(key + '-error')
 }

function getValidityStateError() {
  var validity = $el[0].validity
  return validity.typeMismatch    ? $el.data('type-error')
       : validity.patternMismatch ? $el.data('pattern-error')
       : validity.stepMismatch    ? $el.data('step-error')
       : validity.rangeOverflow   ? $el.data('max-error')
       : validity.rangeUnderflow  ? $el.data('min-error')
       : validity.valueMissing    ? $el.data('required-error')
       :                            null
}

function getGenericError() {
  return $el.data('error')
}

function getErrorMessage(key) {
  return getValidatorSpecificError(key)
      || getValidityStateError()
      || getGenericError()
}

 $.each(this.validators, $.proxy(function (key, validator) {
  var error = null
  if ((getValue($el) || $el.attr('required')) &&
      ($el.data(key) || key == 'native') &&
      (error = validator.call(this, $el))) {
     error = getErrorMessage(key) || error
    !~errors.indexOf(error) && errors.push(error)
  }
 }, this))

if (!errors.length && getValue($el) && $el.data('remote')) {
  this.defer($el, function () {
    var data = {}
    data[$el.attr('name')] = getValue($el)
    $.get($el.data('remote'), data)
      .fail(function (jqXHR, textStatus, error) { errors.push(getErrorMessage('remote') || error) })
      .always(function () { deferred.resolve(errors)})
  })
  } else deferred.resolve(errors)

return deferred.promise()
 }

 Validator.prototype.validate = function () {
var self = this

$.when(this.$inputs.map(function (el) {
  return self.validateInput($(this), false)
})).then(function () {
  self.toggleSubmit()
  self.focusError()
})

return this
 }

 Validator.prototype.focusError = function () {
if (!this.options.focus) return

var $input = this.$element.find(".has-error:first :input")
if ($input.length === 0) return

$('html, body').animate({scrollTop: $input.offset().top - Validator.FOCUS_OFFSET}, 250)
$input.focus()
 }

 Validator.prototype.showErrors = function ($el) {
var method = this.options.html ? 'html' : 'text'
var errors = $el.data('bs.validator.errors')
var $group = $el.closest('.form-group')
var $block = $group.find('.help-block.with-errors')
var $feedback = $group.find('.form-control-feedback')

if (!errors.length) return

errors = $('<ul/>')
  .addClass('list-unstyled')
  .append($.map(errors, function (error) { return $('<li/>')[method](error) 
}))

$block.data('bs.validator.originalContent') === undefined && $block.data('bs.validator.originalContent', $block.html())
$block.empty().append(errors)
$group.addClass('has-error has-danger')

$group.hasClass('has-feedback')
  && $feedback.removeClass(this.options.feedback.success)
  && $feedback.addClass(this.options.feedback.error)
  && $group.removeClass('has-success')
 }

 Validator.prototype.clearErrors = function ($el) {
var $group = $el.closest('.form-group')
var $block = $group.find('.help-block.with-errors')
var $feedback = $group.find('.form-control-feedback')

$block.html($block.data('bs.validator.originalContent'))
$group.removeClass('has-error has-danger has-success')

$group.hasClass('has-feedback')
  && $feedback.removeClass(this.options.feedback.error)
  && $feedback.removeClass(this.options.feedback.success)
  && getValue($el)
  && $feedback.addClass(this.options.feedback.success)
  && $group.addClass('has-success')
 }

 Validator.prototype.hasErrors = function () {
function fieldErrors() {
  return !!($(this).data('bs.validator.errors') || []).length
 }

return !!this.$inputs.filter(fieldErrors).length
 }

 Validator.prototype.isIncomplete = function () {
function fieldIncomplete() {
  var value = getValue($(this))
  return !(typeof value == "string" ? $.trim(value) : value)
  }

 return !!this.$inputs.filter('[required]').filter(fieldIncomplete).length
 }

 Validator.prototype.onSubmit = function (e) {
 this.validate()
 if (this.isIncomplete() || this.hasErrors()) e.preventDefault()
 }

 Validator.prototype.toggleSubmit = function () {
  if (!this.options.disable) return
  this.$btn.toggleClass('disabled', this.isIncomplete() || this.hasErrors())
  }

 Validator.prototype.defer = function ($el, callback) {
callback = $.proxy(callback, this, $el)
if (!this.options.delay) return callback()
window.clearTimeout($el.data('bs.validator.timeout'))
$el.data('bs.validator.timeout', window.setTimeout(callback, this.options.delay))
 }

   Validator.prototype.reset = function () {
   this.$element.find('.form-control-feedback')
  .removeClass(this.options.feedback.error)
  .removeClass(this.options.feedback.success)

 this.$inputs
  .removeData(['bs.validator.errors', 'bs.validator.deferred'])
  .each(function () {
    var $this = $(this)
    var timeout = $this.data('bs.validator.timeout')
    window.clearTimeout(timeout) && $this.removeData('bs.validator.timeout')
  })

 this.$element.find('.help-block.with-errors')
  .each(function () {
    var $this = $(this)
    var originalContent = $this.data('bs.validator.originalContent')

    $this
      .removeData('bs.validator.originalContent')
      .html(originalContent)
  })

  this.$btn.removeClass('disabled')

  this.$element.find('.has-error, .has-danger, .has-success').removeClass('has-error has-danger has-success')

  return this
  }

 Validator.prototype.destroy = function () {
   this.reset()

   this.$element
  .removeAttr('novalidate')
  .removeData('bs.validator')
  .off('.bs.validator')

   this.$inputs
  .off('.bs.validator')

   this.options    = null
   this.validators = null
   this.$element   = null
   this.$btn       = null

   return this
 }

 // VALIDATOR PLUGIN DEFINITION
 // ===========================


 function Plugin(option) {
   return this.each(function () {
  var $this   = $(this)
  var options = $.extend({}, Validator.DEFAULTS, $this.data(), typeof option == 'object' && option)
  var data    = $this.data('bs.validator')

  if (!data && option == 'destroy') return
  if (!data) $this.data('bs.validator', (data = new Validator(this, options)))
  if (typeof option == 'string') data[option]()
   })
   }

 var old = $.fn.validator

 $.fn.validator             = Plugin
 $.fn.validator.Constructor = Validator


 // VALIDATOR NO CONFLICT
 // =====================

 $.fn.validator.noConflict = function () {
   $.fn.validator = old
   return this
   }


   // VALIDATOR DATA-API
   // ==================

   $(window).on('load', function () {
   $('form[data-toggle="validator"]').each(function () {
     var $form = $(this)
     Plugin.call($form, $form.data())
   })
  })

   }(jQuery);

1 个答案:

答案 0 :(得分:0)

您需要在“提交”功能中添加e.preventDefault();,以防止默认的表单提交行为。

您可能还想尝试删除HTML部分中的“方法”和“操作”属性,但我不是百分之百确定。