AngularJS Contact Form with Bootstrap and PHPMailer

The form is styled with Bootstrap. Validation and sending the form data to the server is done with AngularJS. More validation and processing the email is done with PHPMailer on the server.

angularjs-bootstrap-phpmailer-form

In index.html setup the form and add all the Angular directives:

<!DOCTYPE html>
<html>
<head>
    <title>AngularJS Contact Form with Bootstrap and PHPMailer</title>
    <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="style.css">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
    <script src="app.js"></script>
    <script src="controllers.js"></script>
</head>
<body ng-app="contactApp" >
    <div class="vertical-middle">
        <div class="container">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h2 class="panel-title">Contact Form</h2>
                </div>
                <div ng-controller="ContactController" class="panel-body">
                    <form ng-submit="submit(contactform)" name="contactform" method="post" action="" class="form-horizontal" role="form">
                        <div class="form-group" ng-class="{ 'has-error': contactform.inputName.$invalid && submitted }">
                            <label for="inputName" class="col-lg-2 control-label">Name</label>
                            <div class="col-lg-10">
                                <input ng-model="formData.inputName" type="text" class="form-control" id="inputName" name="inputName" placeholder="Your Name" required>
                            </div>
                        </div>
                        <div class="form-group" ng-class="{ 'has-error': contactform.inputEmail.$invalid && submitted }">
                            <label for="inputEmail" class="col-lg-2 control-label">Email</label>
                            <div class="col-lg-10">
                                <input ng-model="formData.inputEmail" type="email" class="form-control" id="inputEmail" name="inputEmail" placeholder="Your Email" required>
                            </div>
                        </div>
                        <div class="form-group" ng-class="{ 'has-error': contactform.inputSubject.$invalid && submitted }">
                            <label for="inputSubject" class="col-lg-2 control-label">Subject</label>
                            <div class="col-lg-10">
                                <input ng-model="formData.inputSubject" type="text" class="form-control" id="inputSubject" name="inputSubject" placeholder="Subject Message" required>
                            </div>
                        </div>
                        <div class="form-group" ng-class="{ 'has-error': contactform.inputMessage.$invalid && submitted }">
                            <label for="inputMessage" class="col-lg-2 control-label">Message</label>
                            <div class="col-lg-10">
                                <textarea ng-model="formData.inputMessage" class="form-control" rows="4" id="inputMessage" name="inputMessage" placeholder="Your message..." required></textarea>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-lg-offset-2 col-lg-10">
                                <button type="submit" class="btn btn-default" ng-disabled="submitButtonDisabled">
                                    Send Message
                                </button>
                            </div>
                        </div>
                    </form>
                    <p ng-class="result" style="padding: 15px; margin: 0;">{{ resultMessage }}</p>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

Assign a variable to the Angular app in app.js:

var app = angular.module('contactApp', []);

Add a controller to the app for processing the form. Form data is sent via ajax to contact-form.php using Angular’s $http service:

app.controller('ContactController', function ($scope, $http) {
    $scope.result = 'hidden'
    $scope.resultMessage;
    $scope.formData; //formData is an object holding the name, email, subject, and message
    $scope.submitButtonDisabled = false;
    $scope.submitted = false; //used so that form errors are shown only after the form has been submitted
    $scope.submit = function(contactform) {
        $scope.submitted = true;
        $scope.submitButtonDisabled = true;
        if (contactform.$valid) {
            $http({
                method  : 'POST',
                url     : 'contact-form.php',
                data    : $.param($scope.formData),  //param method from jQuery
                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) { //success comes from the return json object
                    $scope.submitButtonDisabled = true;
                    $scope.resultMessage = data.message;
                    $scope.result='bg-success';
                } else {
                    $scope.submitButtonDisabled = false;
                    $scope.resultMessage = data.message;
                    $scope.result='bg-danger';
                }
            });
        } else {
            $scope.submitButtonDisabled = false;
            $scope.resultMessage = 'Failed :(  Please fill out all the fields.';
            $scope.result='bg-danger';
        }
    }
});

The actual emailing is done in contact-form.php on the server. Here some additional validation is done to ensure the form has been filled out. Then an instance of PHPMailer is created and the mail is sent. The page sends back a success or failure message to the Angular $http service:

<?php
require_once 'phpmailer/PHPMailerAutoload.php';

if (isset($_POST['inputName']) && isset($_POST['inputEmail']) && isset($_POST['inputSubject']) && isset($_POST['inputMessage'])) {

    //check if any of the inputs are empty
    if (empty($_POST['inputName']) || empty($_POST['inputEmail']) || empty($_POST['inputSubject']) || empty($_POST['inputMessage'])) {
        $data = array('success' => false, 'message' => 'Please fill out the form completely.');
        echo json_encode($data);
        exit;
    }

    //create an instance of PHPMailer
    $mail = new PHPMailer();

    $mail->From = $_POST['inputEmail'];
    $mail->FromName = $_POST['inputName'];
    $mail->AddAddress('something@test.com'); //recipient 
    $mail->Subject = $_POST['inputSubject'];
    $mail->Body = "Name: " . $_POST['inputName'] . "\r\n\r\nMessage: " . stripslashes($_POST['inputMessage']);

    if (isset($_POST['ref'])) {
        $mail->Body .= "\r\n\r\nRef: " . $_POST['ref'];
    }

    if(!$mail->send()) {
        $data = array('success' => false, 'message' => 'Message could not be sent. Mailer Error: ' . $mail->ErrorInfo);
        echo json_encode($data);
        exit;
    }

    $data = array('success' => true, 'message' => 'Thanks! We have received your message.');
    echo json_encode($data);

} else {

    $data = array('success' => false, 'message' => 'Please fill out the form completely.');
    echo json_encode($data);

}

View a demo here. Download the source files.

Links:
- Submitting AJAX Forms: The AngularJS Way
- AngularJS ngClass
- AngularJS ngDisabled
- About $valid and $invalid
- I got the Bootstrap form from a good blog, but I forgot to bookmark it. I’ll add the link when I find it again.

Posted in Uncategorized | 24 Comments

AngularJS Directive HTML5 Video with Flash Fallback

Implementing the HTML5 Video with Flash Fallback example as an AngularJS Directive.

html5 video with flash fallback in chrome

In index.html apply the custom directive (html5-fallback-video) as an attribute on an element:

<!DOCTYPE html>
<html ng-app="myApp"> 
<head>
  <title>HTML5 Video with Flash Fallback AngularJS Directive Example</title>
  <script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.1/modernizr.min.js"></script>
  <script src="flowplayer/flowplayer-3.2.12.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
  <script src="app.js"></script>
  <style>
    html, body {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      display: table;
      background-color: #000;
    }
    #video {
      display: table-cell;
      vertical-align: middle;
      text-align: center;
    }
  </style>
</head>
<body>
  <div id="video" 
  html5-fallback-video 
  webm-url="media/big_buck_bunny.webmsd.webm" 
  mp4-url="media/big_buck_bunny.mp4" 
  video-width="854" 
  video-height="480" 
  splash-image="splash-screen.jpg">
</div>
</body>
</html>

The directive itself is defined in app.js. Modernizr determines if the browser supports HTML5 video in the directive’s link method. If the browser does not support HTML5 video, Flowplayer plays it with Flash:

var app = angular.module('myApp', []);
//attach a directive to app which will display video
app.directive('html5FallbackVideo', function () {
    return {
        restrict: 'A', //this means the direct must be declared as an attribute on an element
        replace: false, //don't replace the surrounding element with the template code
        link: function (scope, element, attrs) { // manipulate the DOM in here
            if (!Modernizr.video) { //if html5 video is not supported start flowplayer
                //alert('flash video');
                flowplayer("flash-player", "flowplayer/flowplayer-3.2.16.swf", {
                    clip: {
                        url: scope.mp4Url,
                        autoPlay: false,
                        autoBuffering: true,
                        scaling: "fit"
                    },
                    canvas: {
                        backgroundColor: "#000000",
                        backgroundGradient: "none"
                    }
                });
            }
        },
        scope: {
            webmUrl: '@', //binds property value to the element's attribute
            mp4Url: '@',
            videoWidth: '@',
            videoHeight: '@',
            splashImage: '@'
        },
        templateUrl: 'html5-fallback-video.html' //contains the video code
    }
}); 

The directive loads an external template (html5-fallback-video.html) which contains the HTML code for the video players:

<div ng-style="{'width':'{{ videoWidth }}px','height':'{{ videoHeight }}px}">
	<video width="{{ videoWidth }}" height="{{ videoHeight }}" poster="{{ splashImage }}" controls >
		<source src="{{ mp4Url }}" type="video/mp4" />
		<source src="{{ webmUrl }}" type="video/webm" />
		<a id="flash-player" ng-style="{'width':'{{ videoWidth }}px','height':'{{ videoHeight }}px','display':'block','margin':'0 auto'}"></a>
	</video>
</div>

View a demo here. Download the source files.

Links:
- ngStyle Background
- AngularJS Directives
- Detecting HTML5 Features

Posted in Uncategorized | 1 Comment

AngularJS Example: $rootScope vs $scope

In this example a color variable is set on the $rootScope at the beginning, inside the run block. There is only one $rootScope, so this is kind of like setting a global variable. Later inside GroverController a color variable is set on it’s $scope, this overrides the $rootScope inside this controller. View a demo here.

<!DOCTYPE html>
<html ng-app="myApp"> 
<head>
  <title>$rootScope and $scope</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
</head>
<body>
  <p>Big Bird is {{ color }}.</p>
  <div ng-controller="GroverController">
    <p>Grover is {{ color }}.</p>
  </div>
  <div ng-controller="SunController">
    <p>The sun is {{ color }}.</p>
  </div>
  <script type="text/javascript">
    var app = angular.module('myApp', []).run(function($rootScope) {
      $rootScope.color = 'yellow';
    });
    app.controller('GroverController', function($scope) {
      $scope.color = 'blue';
    });
    app.controller('SunController', function($scope) {
    });
  </script>
</body>
</html>
Posted in Uncategorized | 3 Comments

Cascades QML Create Tabs Dynamically From JSON

Using XMLHttpRequest in QML and ComponentDefinition to create tabs from a JSON feed.

import bb.cascades 1.2

TabbedPane {
    showTabsOnActionBar: false
    attachedObjects: [
        ComponentDefinition { //allows us to create tabs dynamically
            id: tabControlDefinition
            Tab {
                property string textString
                title: textString
                Page {
                    Container {
                        Label {
                            text: textString
                        }
                    }
                }
            }
        }
    ]
    onCreationCompleted: {
        //get the networks and add them to the drop down menu
        var request = new XMLHttpRequest()
        request.onreadystatechange = function() {
            if (request.readyState == 4) { //4 means the request is complete
                var response = request.responseText
                response = JSON.parse(response)
                var tabComponents = response.networks
                for (var i = 0; i < tabComponents.length; i ++) {
                    var createdTab = tabControlDefinition.createObject();
                    createdTab.textString = tabComponents[i]
                    console.log(tabComponents[i])
                    add(createdTab);
                }
            }
        }
        request.open("GET", "http://example.json.php", true)
        request.send()
    }
}
Posted in Uncategorized | 1 Comment