/** * @constructor * * @param {String} name * @param {String} type One of Vehicle.TYPE_*. */ var Vehicle = function(name, type) { this.name = name; this.type = type; this.error = null; }; Vehicle.TYPE_CAR = 'car'; Vehicle.TYPE_MOTORCYCLE = 'motorcycle'; Vehicle.displayTypes = {}; Vehicle.displayTypes[Vehicle.TYPE_CAR] = 'Car'; Vehicle.displayTypes[Vehicle.TYPE_MOTORCYCLE] = 'Motorcycle'; /** * @return {String} */ Vehicle.prototype.getDisplayType = function() { return Vehicle.displayTypes[this.type]; }; /** * @return {Vehicle} A clone of this vehicle. */ Vehicle.prototype.clone = function() { return angular.extend(new Vehicle(), this); }; /** * @return {Boolean} TRUE if this vehicle's data is valid, FALSE if not. * If FALSE, this.error is populated with a message. */ Vehicle.prototype.validate = function() { var valid = true; this.error = null; if(this.name === '') { valid = false; this.error = 'Vehicle name required.'; } return valid; }; /** * @constructor */ var GarageCtrl = function($scope) { $scope.vehicles = [ new Vehicle('2011 Nissan Frontier', Vehicle.TYPE_CAR), new Vehicle('2007 Honda CRF450R', Vehicle.TYPE_MOTORCYCLE) ]; // Expose Vehicle class to scope and initialize the new vehicle $scope.Vehicle = Vehicle; $scope.newVehicle = new Vehicle('', Vehicle.TYPE_CAR); /** * @param {Vehicle} Vehicle Vehicle to delete. */ $scope.deleteVehicle = function(vehicle) { for(var i=0; i<$scope.vehicles.length; ++i) { if($scope.vehicles[i] === vehicle) { $scope.vehicles.splice(i, 1); break; } } }; /** * @param {Vehicle|Object} newVehicle Vehicle to add, or generic object castable to a Vehicle. */ $scope.addVehicle = function(newVehicle) { newVehicle instanceof Vehicle || (newVehicle = angular.extend(new Vehicle(), newVehicle)); if(!newVehicle.validate()) { alert(newVehicle.error); } // Input OK else { // Clone it onto our set $scope.vehicles.push(newVehicle.clone()); } }; };
<div ng-app ng-controller="GarageCtrl"> <h1>My Garage</h1> <ul> <li ng-repeat="vehicle in vehicles"> <strong>{{vehicle.getDisplayType()}}</strong> - <span>{{vehicle.name}}</span> - <a class="deleteBtn" href="" ng-click="deleteVehicle(vehicle)">delete</a> </li> </ul> <form ng-submit="addVehicle(newVehicle); newVehicle.name = ''"> <select ng-model="newVehicle.type" ng-options="type as displayType for (type, displayType) in Vehicle.displayTypes"></select> <input type="text" ng-model="newVehicle.name" placeholder="Vehicle name" /> <button type="submit">Add Vehicle</button> </form> <p><em>...</em></p> <p><em>later on down the page</em></p> <p><em>...</em></p> <p ng-show="!vehicles.length"> Your garage looks a little empty. Do you want <a ng-click="addVehicle({name: 'Ferarri', type: Vehicle.TYPE_CAR})">a Ferrari</a>? </p> <p ng-show="vehicles.length">You have {{vehicles.length}} vehicle<span ng-show="vehicles.length != 1">s</span> in your garage.</p> <form ng-submit="addVehicle({name: addCarName || '', type: Vehicle.TYPE_CAR}); addCarName = ''"> <label for="addCarName">Add a car:</label> <input type="text" ng-model="addCarName" id="addCarName" placeholder="Car name" /> <button type="submit">OK</button> </form> <form ng-submit="addVehicle({name: addMotoName || '', type: Vehicle.TYPE_MOTORCYCLE}); addMotoName = ''"> <label for="addMotoName">Add a motorcycle:</label> <input type="text" ng-model="addMotoName" id="addMotoName" placeholder="Motorcycle name" /> <button type="submit">OK</button> </form> </div>