Skip to content

ARCHIVED-mean-stack/session-10

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#MEAN Session 10

##Homework

  • add bootstrap styles to the edit pirate form
  • add validation to the edit pirate form
  • add a cancel botton tot he edit pirate form

##Update Pirate

Use edit in place in pirate-detail.html:

<h1>Pirate Detail View</h1>
<div ng-hide="$ctrl.editorEnabled">
    <dl>
        <dt>Name</dt>
        <dd>{{ $ctrl.pirate.name }}</dd>
        <dt>Vessel</dt>
        <dd>{{ $ctrl.pirate.vessel }}</dd>
        <dt>Weapon</dt>
        <dd>{{ $ctrl.pirate.weapon }}</dd>
        <dt>ID</dt>
        <dd>{{ $ctrl.pirate._id }}</dd>
    </dl>
    <button ng-click="$ctrl.enableEditor($ctrl.pirate)">Edit</button>
</div>
<div ng-show="$ctrl.editorEnabled">
    <form ng-submit="$ctrl.savePirate($ctrl.pirate, $ctrl.pirate._id)" name="updatePirate">
        <label>Name</label>
        <input ng-model="$ctrl.pirate.name">
        <label>Vessel</label>
        <input ng-model="$ctrl.pirate.vessel">
        <label>Weapon</label>
        <input ng-model="$ctrl.pirate.weapon">
        <label>ID</label>
        <input ng-model="$ctrl.pirate._id">
        <input type="submit" value="Save">
    </form>
</div>

<button type="submit" ng-click="$ctrl.back()">Back</button>

Add the feature to pirate-detail.component.js:

angular.module('pirateDetail', []).component('pirateDetail', {
    templateUrl: '/templates/pirate-detail.html',

    controller: ['$scope', '$http', '$routeParams', '$location',
        function PirateDetailController($http, $routeParams, $location) {
            var self = this;
            $http.get('/api/pirates/' + $routeParams.pirateId)
                .then(function (res) {
                    self.pirate = res.data;
                });

            self.back = function () {
                $location.path('/');
            }

            self.editorEnabled = false;

            self.enableEditor = function () {
                self.editorEnabled = true;
            };

            self.disableEditor = function () {
                self.editorEnabled = false;
            };

            self.savePirate = function (pirate, pid) {
                console.log(pirate.name)
                $http.put('/api/pirates/' + pid, pirate)
                    .success(function (res) {
                        self.editorEnabled = false;
                    })
            }
        }
    ]
});

Test buttons. Test editing pirate.

##GULP

Package.json from Image Gallery exercise:

  "devDependencies": {
    "browser-sync": "^2.16.0",
    "gulp": "^3.9.1",
    "gulp-sass": "^2.3.2",
    "gulp-sourcemaps": "^1.6.0"
  }

Server.js from Image Gallery exercise:

var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var browserSync = require('browser-sync')
var express = require('express');

var sassOptions = {
	errLogToConsole: true,
	outputStyle: 'expanded'
};

var sassSources = './app/public/sass/**/*.scss';
var sassOutput = './app/public/css';
var htmlSource = './app/public/**/*.html';

var app = express();
var port = process.env.PORT || 3000;

gulp.task('sass', function(){
	return gulp.src(sassSources)
	.pipe(sourcemaps.init())
	.pipe(sass(sassOptions).on('error', sass.logError))
	.pipe(sourcemaps.write('.'))
	.pipe(gulp.dest(sassOutput))
	.pipe(browserSync.stream())
});

function listening () {
	browserSync({
		proxy: 'localhost:' + port,
		browser: "google chrome"
	});
	gulp.watch(sassSources, ['sass']);
	gulp.watch(htmlSource).on('change', browserSync.reload);
}

app.use(express.static('./app/public'));

app.listen(port, listening);

Integrate into our server.js:

var express = require('express');
var app = express();
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var mongoUri = 'mongodb://localhost/rest-apis';

var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var browserSync = require('browser-sync')

var sassOptions = {
    errLogToConsole: true,
    outputStyle: 'expanded'
};

var sassSources = './assets/scss/**/*.scss';
var sassOutput = './assets/css';
var htmlSource = './assets/**/*.html';

var port = process.env.PORT || 3004;

gulp.task('sass', function() {
    return gulp.src(sassSources)
        .pipe(sourcemaps.init())
        .pipe(sass(sassOptions).on('error', sass.logError))
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(sassOutput))
        .pipe(browserSync.stream())
});

function listening() {
    browserSync({
        proxy: 'localhost:' + port,
        browser: "google chrome"
    });
    gulp.watch(sassSources, ['sass']);
    gulp.watch(htmlSource).on('change', browserSync.reload);
}

var db = mongoose.connection;
mongoose.connect(mongoUri);

app.use(express.static('assets'))

app.use(bodyParser.json());

db.on('error', function() {
    throw new Error('unable to connect at' + mongoUri);
})

require('./models/pirate');
require('./routes')(app);

app.listen(port, listening);
console.log('port 3004');

##Form Validation - HTML5

The fieldset element functions as a structural container for different sections within a form element.

The label element attaches descriptive information to form elements like input fields, radiobuttons, textareas. The for attribute: the value of the attribute is the ID of a <form> element in the same document. Clicking on it places the focus on the input element.

Other data types

<label for="email">Email:</label> 
<input id="email" type="email" name="email" required placeholder="email@example.com" />

<label for="website">Website:</label> 
<input id="website" type="url" name="website" required placeholder="http://www.example.com" />

<label for="number">Number:</label> 
<input id="number" type="number" name="number" min="0" max="10" step="2" required placeholder="Even num < 10">

<label for="range">Range:</label> 
<input id="range" type="range" name="range" min="0" max="10" step="2" />

<label for="date">Date</label> 
<input id="date" type="date" name="date" />

<label for="message">Message:</label> 
<textarea id="message" name="message" required></textarea>

<input type="submit" value="Send Message" />

Note: styling placeholder text

::-webkit-input-placeholder {
   color: red;
}
:-moz-placeholder { /* Firefox 18- */
   color: red;  
}
::-moz-placeholder {  /* Firefox 19+ */
   color: red;  
}

Autofocus

<input type="text" name="name" required placeholder="Name" autofocus />

Auto caps and correct

<input type="text" name="test1" autocapitalize="off" />
<input type="text" name="test2" autocorrect="off" />

Email vs. type="text"

<label for="email">E-mail</label>
<input name="email" id="email" type="email" required />

Input type = URL

<label for="website">Website</label>
<input name="website" id="website" type="url" />

novalidation

<form name=”” action=”” novalidate >

##Bootstrap

Add bootstrap sass

http://getbootstrap.com/css/

http://getbootstrap.com/components/

Clean the repo and put assets folder in scss.

Edit the main sass file: @import 'assets/stylesheets/bootstrap';

Edit index.html:

<body>
    <div class="container" ng-view></div>
</body>

Responsive grid - http://getbootstrap.com/css/#grid-example-mixed-complete

Apply to pirates-view.html:

<div class="col-xs-12">
    <h1>Pirates View</h1>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
    <div class="panel panel-primary">
        <div class="panel-heading">
            <h2 class="panel-title">Pirates View</h2>
        </div>
        <div class="list-group">
            <ul>
                <li class="list-group-item" ng-repeat="pirate in pirates">
                    <a href="#/pirates/{{ pirate._id }}">{{ pirate.name }}</a>
                    <button ng-click="deletePirate($index, pirate._id)" type="button" class="close" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                </li>
            </ul>
        </div>
    </div>
</div>

<div class="col-xs-12 col-sm-6 col-md-6">
    <h3>Add a Pirate</h3>
    <form ng-submit="addPirate(pirate)" name="addform" novalidate>
        <fieldset>
            <div class="form-group">
                <label for="pirate-name">Name</label>
                <input type="text" class="form-control" placeholder="Name" ng-model="pirate.name" />
            </div>
            <div class="form-group">
                <label for="pirate-vessel">Vessel</label>
                <input type="text" ng-model="pirate.vessel" class="form-control" id="pirate-vessel" placeholder="Vessel" />
            </div>
            <div class="form-group">
                <label for="pirate-vessel">Weapon</label>
                <input type="text" ng-model="pirate.weapon" class="form-control" id="pirate-weapon" placeholder="Weapon" />
            </div>
            <button type="submit" class="btn btn-primary">Add Pirate</button>
        </fieldset>
    </form>
</div>

Test all functions.

##Form Validation - Angular

Some CSS selectors available to us:

.ng-valid       {  }
.ng-invalid     {  }
.ng-pristine    {  }
.ng-dirty       {  }
.ng-touched     {  }

See the Angular Forms Guide for complete documentation.

Add validation to our add pirate form.

  • Add name attribute to form
  • Add required to form fields
  • Add name attributes for fields
  • novalidate - is used to disable browser's native form validation
  • Add paragraphs using ng-show

<form ng-submit="addPirate(pirate)" name="addform" novalidate>
    <fieldset>
        <div class="form-group">
            <label for="pirate-name">Name</label>
            <input type="text" name="pname" ng-model="name" class="form-control" id="pirate-name" placeholder="Name" ng-minlength="4" ng-required="true">
            <p ng-show="addform.pname.$invalid">You must enter a name.</p>
        </div>
        <div class="form-group">
            <label for="pirate-vessel">Vessel</label>
            <input type="text" name="pvessel" ng-model="pirate.vessel" class="form-control" id="pirate-vessel" placeholder="Vessel" ng-required="true">
            <p ng-show="addform.pvessel.$invalid">You must enter a vessel.</p>
        </div>
        <div class="form-group">
            <label for="pirate-vessel">Weapon</label>
            <input type="text" name="pweapon" ng-model="pirate.weapon" class="form-control" id="pirate-weapon" placeholder="Weapon" ng-required="true">
            <p ng-show="addform.pweapon.$invalid">You must enter a weapon.</p>
        </div>
        <button type="submit" class="btn btn-primary">Add Pirate</button>
    </fieldset>
</form>

The paras appear and then disappear when valid. Use && addform.pname.$touched to make them appear afterwards.

Add ng-disabled="addform.$invalid" to the submit button.

<form ng-submit="addPirate(pirate)" name="addform" novalidate>
    <fieldset>
        <div class="form-group">
            <label for="pirate-name">Name</label>
            <input name="pname" type="text" class="form-control" placeholder="Name" ng-model="pirate.name" ng-required="true" />
            <p ng-show="addform.pname.$invalid && addform.pname.$touched">You must enter a name.</p>
        </div>
        <div class="form-group">
            <label for="pirate-vessel">Vessel</label>
            <input name="pvessel" type="text" ng-model="pirate.vessel" class="form-control" id="pirate-vessel" placeholder="Vessel" ng-required="true" />
            <p ng-show="addform.pvessel.$invalid && addform.pname.$touched">You must enter a vessel.</p>
        </div>
        <div class="form-group">
            <label for="pirate-vessel">Weapon</label>
            <input name="pweapon" type="text" ng-model="pirate.weapon" class="form-control" id="pirate-weapon" placeholder="Weapon" ng-required="true" />
            <p ng-show="addform.pweapon.$invalid && addform.pname.$touched">You must enter a weapon.</p>
        </div>
        <button type="submit" ng-disabled="addform.$invalid" class="btn btn-primary">Add Pirate</button>
    </fieldset>
</form>

Add error class to paragraphs:

<p class="error" ng-show="addform.pname.$invalid && addform.pname.$touched">You must enter a name.</p>
...
<p class="error" ng-show="addform.pvessel.$invalid && addform.pvessel.$touched">You must enter a vessel.</p>
...
<p class="error" ng-show="addform.pweapon.$invalid && addform.pweapon.$touched">You must enter a weapon.</p>
input.ng-invalid.ng-touched {
    border: 1px solid red;
}

input.ng-valid.ng-touched {
    border: 1px solid green;
}

button[disabled] {
background: gray;
}

.error {
    color: red;
} 

Upon submission the form still registers input fields as dirty and we see the error paras.

Examine the FormController method

$scope.addPirate = function (data) {
    $http.post('/api/pirates/', data)
        .success(function () {
            $scope.pirates.push(data);
            $scope.pirate = {}
            $scope.addform.$setPristine();
            $scope.addform.$setUntouched();
        })
};

add message to top of form:

<p ng-show="message">A pirate named {{message}} was added.</p>

$scope.addPirate = function(data) {
    $http.post('/api/pirates/', data)
        .success(function() {
            $scope.message = data.name;
            $scope.pirates.push(data);
            $scope.pirate = {}
            $scope.addform.$setPristine();
            $scope.addform.$setUntouched();
        })
};

Use ng-class and add bootstrap text-success / text-warning

<div class="form-group" ng-class="{ 'has-error': addform.pname.$touched && addform.name.$invalid }">

<h3>Add a Pirate</h3>
<p class="text-success" ng-show="message">A pirate named {{message}} was added.</p>
<form ng-submit="addPirate(pirate)" name="addform" novalidate="">
    <fieldset>
        <div class="form-group" ng-class="{ 'has-error': addform.pname.$touched && addform.pname.$invalid }">
            <label class="control-label" for="pirate-name">Name</label>
            <input type="text" name="pname" ng-model="pirate.name" class="form-control" id="pirate-name" placeholder="Name" ng-required="true">
            <p class="text-warning" ng-show="addform.pname.$invalid && addform.pname.$touched">You must enter a name.</p>
        </div>
        <div class="form-group" ng-class="{ 'has-error': addform.pvessel.$touched && addform.pvessel.$invalid }">
            <label for="pirate-vessel">Vessel</label>
            <input type="text" name="pvessel" ng-model="pirate.vessel" class="form-control" id="pirate-vessel" placeholder="Vessel" ng-required="true">
            <p class="text-warning" ng-show="addform.pvessel.$invalid && addform.pvessel.$touched">You must enter a vessel.</p>
        </div>
        <div class="form-group" ng-class="{ 'has-error': addform.pweapon.$touched && addform.pweapon.$invalid }">
            <label for="pirate-vessel">Weapon</label>
            <input type="text" name="pweapon" ng-model="pirate.weapon" class="form-control" id="pirate-weapon" placeholder="Weapon" ng-required="true">
            <p class="text-warning" ng-show="addform.pweapon.$invalid && addform.pweapon.$touched">You must enter a weapon.</p>
        </div>
        <button type="submit" class="btn btn-primary" ng-disabled="addform.$invalid">Add Pirate</button>
    </fieldset>
</form>

See http://getbootstrap.com/css/#forms-control-validation for details on using this class.

Use text-warning for the paragraphs.

Use class="control-label" for the labels.

Here's one form-group sample that uses bootstrap:

<div class="form-group" ng-class="{ 'has-error': addform.pname.$touched && addform.pname.$invalid }">
            <label class="control-label" for="pirate-name">Name</label>
            <input type="text" name="pname" ng-model="pirate.name" class="form-control" id="pirate-name" placeholder="Name" ng-required="true">
            <p class="text-warning" class="help-block" ng-show="addform.pname.$invalid && addform.pname.$touched">You must enter a name.</p>
        </div>

We no longer need some of our classes:

@import 'assets/stylesheets/bootstrap';

/*input.ng-invalid.ng-touched {
    border: 1px solid red;
}*/

input.ng-valid.ng-touched {
    border: 1px solid green;
}

button[disabled] {
background: gray;
}

/*.error {
    color: red;
}*/

We can extend ng-class to use some of the other available formatting in bootstrap.

Here's a sample from the Angular ng-class directive documentation

<p ng-class="{strike: deleted, bold: important, 'has-error': error}">

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors