AngularJS应用GubHub

        AngularJS实例GutHub是一款简单管理应用,主要的特性如下:

1.两列布局

2.在左侧有一个导航条

3.允许你创建新菜谱

4.允许你浏览现有的菜谱列表

        主视图位于右侧,主视图将会根据具体的URL刷新,可以显示菜谱列表、菜谱项目详情,以及用来添加或编辑菜谱的表单。

        本文源码下载地址:https://github.com/johnnymitrevski/gutHub

工程结构图:

controllers.js

//Setup the GutHub angular module
var app = angular.module('guthub', ['guthub.directives', 'guthub.services']);

//Update the baseUrl to match the directory the app is deployed on the web server. Leave blank if '/'.
var baseUrl = "";

/**
 * Specify the various routes we have in our application. For each route we specify:
 * 1) The controller that backs it up.
 * 2) The template to load.
 * 3) The resolve object (Optional). This tells angular JS that each of the resolve keys need to be meet
 * before the route can be displayed to  the user. For us, we want to load all the recipe data before we
 * display the page. If the resolve function returns a $q (promise) then AngularJs is smart enough to wait
 * for the promise to get resolved before it proceeds. That means wait till the server responds.
 */
app.config(['$routeProvider', function($routeProvider) {

    $routeProvider.when('/', {
        controller: 'ListCtrl',

        resolve: {
            recipes: function(MultiRecipeLoader) {
                return MultiRecipeLoader();
            }
        },
        templateUrl: baseUrl + '/GutHub/views/list.html'
    }).when('/edit/:recipeId', {
            controller: 'EditCtrl',
            resolve: {
                recipe: function(RecipeLoader) {
                    return RecipeLoader();
                }
            },
            templateUrl: baseUrl + '/GutHub/views/recipeForm.html'
        }).when('/view/:recipeId', {
            controller: 'ViewCtrl',
            resolve: {
                recipe: function(RecipeLoader) {
                    return RecipeLoader();
                }
            },
            templateUrl: baseUrl + '/GutHub/views/viewRecipe.html'
        }).when('/new', {
            controller: 'NewCtrl',
            templateUrl:baseUrl + '/GutHub/views/recipeForm.html'
        }).otherwise({redirectTo: '/'});
}]);

/**
 * List the recipes
 */
app.controller('ListCtrl',['$scope','recipes',function($scope, recipes) {
    //$scope.recipes = recipes;
	$scope.recipes = [
	   { id:1, title:"cookies", description: "Delicious, crisp on the outside, chewy" + " on the outside, oozing with chocolatey goodness " + "cookies. The best kind", ingredients: [ { amount: "1", amountUnits: "packet", ingredientName: "Chips Ahoy" } ], instructions: "1. Go buy a packet of Chips Ahoy\ n" + "2. Heat it up in an oven\ n" + "3. Enjoy warm cookies\ n" + "4. Learn how to bake cookies from somewhere else" }
	];
}]);

/**
 * View a recipe
 */
app.controller('ViewCtrl', ['$scope','$location','recipe', function($scope, $location, recipe) {
    $scope.recipe = recipe;
    $scope.edit = function() {
        $location.path('/edit/' + recipe.id);
    };
}]);

/**
 * Exposes save() and remove() functions to scope.
 *
 * save() will save the current recipe and then redirect to the view screen
 * of the same recipe.
 *
 * remove() removes the recipe from the scope and redirects the uses to the
 * main landing page.
 */
app.controller('EditCtrl', ['$scope','$location','recipe', function($scope, $location, recipe) {

    $scope.recipe = recipe;

    $scope.save = function() {
        $scope.recipe.$save(function(recipe){
            $location.path(baseUrl + '/GutHub/view/' + recipe.id);
        });
    };

    $scope.remove = function() {
        delete $scope.recipe;   //Doesn't remove it from the server. Only from $scope.

        $location.path(baseUrl + '/');
    };
}]);

/**
 * Create a new recipe.
 */
app.controller('NewCtrl',['$scope', '$location', 'Recipe', function($scope, $location, Recipe){
    $scope.recipe = new Recipe({
        ingredients: [{}]
    });

    $scope.save = function() {
        $scope.recipe.$save(function(recipe) {
            $location.path(baseUrl + '/view/' + recipe.id);
        });
    };
}]);

/**
 * Edit the ingredients. It inherits $scope from the parent controller.
 */
app.controller('IngredientsCtrl', ['$scope', function($scope) {

    $scope.addIngredient = function() {
        var ingredients = $scope.recipe.ingredients;
        ingredients[ingredients.length] = {};
    };

    $scope.removeIngredient = function(index) {
        $scope.recipe.ingredients.splice(index, 1);
    };
}]);

directives.js

var directives = angular.module('guthub.directives',[]);

directives.directive('butterbar',['$rootScope', function($rootScope){
    return {
        link: function(scope, element, attrs) {

            element.addClass('hide'); //Hide the element upfront

            //Watch the $routeChangeStart and remove the hide css, therefore show
            $rootScope.$on('$routeChangeStart', function() {
                element.removeClass('hide');
            });

            //Watch the $routeChangeSuccess and remove add the hide css, therefore hide
            $rootScope.$on('$routeChangeSuccess', function() {
                element.addClass('hide');
            });
        }
    };
}]);

/**
 * Calls the focus() method on the current element.
 *
 * Call it by adding the focus attribute on any input element.
 * i.e. <input type="text" focus></input>
 * Therefore when the page loads, that element immediately gets the focus.
 */
directives.directive('focus', function() {
    return {
        link: function(scope, element, attrs) {
            element[0].focus();
        }
    };
});

services.js

var services = angular.module('guthub.services',['ngResource']);

/**
 * Recipe service.
 *
 * Uses $resource, which is is a RESTful handle that encapsulates lower level $http service.
 *
 * Recipe can now be used an argument injected into our controllers. The following methods are built in:
 * Recipe.get();
 * Recipe.save();
 * Recipe.delete();
 * Recipe.remove();
 * Recipe.delete();
 *
 * Useage: if we pass in an object with an id field, then the value of that field will be
 * added to the end of the URL.
 * Calling Recipe.get({id:15}) will make a call to /recipes/15
 *
 * For example:
 * var recipe = new Recipe(existingRecipeObj);
 * recipe.$save(); - this calls a POST request
 */
services.factory('Recipe',['$resource', function($resource){
    return $resource('/GutHub/recipes/:id',{id: '@id'});
}]);

/**
 * Load all recipes.
 */
services.factory('MultiRecipeLoader', ['Recipe', '$q', function(Recipe,$q){
    return function() {
        var delay = $q.defer();

        Recipe.query(function(recipesData) {
            delay.resolve(recipesData);
        }, function() {
            //delay.reject('Unable to fetch recipes');
            delay.resolve([{id:1, title:"cookies"}, {id:2, title:"farts"}]);
        });

        return delay.promise;
    };
}]);

/**
 * Load a single recipe.
 */
services.factory('RecipeLoader', ['Recipe','$route', '$q', function(Recipe, $route, $q){
    return function() {
        var delay = $q.defer();
        Recipe.get({id: $route.current.params.recipeId}, function(recipeData) {
            delay.resolve(recipeData);
        }, function() {
            //delay.reject('Unable to fetch recipe ' + $route.current.params.recipeId);
            delay.resolve({ id:1, title:"cookies", description: "Delicious, crisp on the outside, chewy" + " on the outside, oozing with chocolatey goodness " + "cookies. The best kind", ingredients: [ { amount: "1", amountUnits: "packet", ingredientName: "Chips Ahoy" } ], instructions: "1. Go buy a packet of Chips Ahoy\ n" + "2. Heat it up in an oven\ n" + "3. Enjoy warm cookies\ n" + "4. Learn how to bake cookies from somewhere else" });
        });

        return delay.promise;
    }
}]);

index.html

<!DOCTYPE html>

<html lang="en" ng-app="guthub">
<head>
<title>GutHub - Create and Share</title>
<script src="scripts/vendor/angular.js"></script>
<script src="scripts/vendor/angular-resource.js"></script>
<script src="scripts/directives/directives.js"> </script>
<script src="scripts/services/services.js"> </script>
<script src="scripts/controllers/controllers.js"></script>
<link href="scripts/vendor/bootstrap/css/bootstrap.css" rel="stylesheet">
</head>
<body>
    <header>
        <h1>GutHub</h1>
    </header>
    <div butterbar>Loading...</div>

    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span2">
            <!--Sidebar-->
            <div id="focus">
                <a href="#/new">New Recipe</a>
            </div>
            <div>
                <a href="#/">Recipe List</a>
            </div>
            </div>
            <div class="span10">
                <div ng-view></div>
            </div>
        </div>
    </div>
</body>
</html>

list.html

<h3>Recipe List</h3>
<ul class="recipes">
    <li ng-repeat="recipe in recipes">
        <div>
            <a href="#/view/{{ recipe.id }}">{{ recipe.title }}</a>
        </div>
    </li>
</ul>

recipeForm.html

<h2>Edit Recipe</h2>

<form name="recipeForm" ng-submit="save()" class="form-horizontal">
    <div class="control-group">
        <label class="control-label" for="title">Title:</label>
        <div class="controls">
            <input ng-model="recipe.title" class="input-xlarge" id="title" focus>
        </div>
    </div>
    <div class="control-group">
        <label class="control-label" for="description">Description:</label>
        <div class="controls">
            <textarea ng-model="recipe.description" class="input-xlarge" id="description"></textarea>
        </div>
    </div>
    <div class="control-group">
        <label class="control-label" for="ingredients">Ingredients:</label>
        <div class="controls">
            <ul id="ingredients" class="unstyled" ng-controller="IngredientsCtrl">
                <li ng-repeat="ingredient in recipe.ingredients">
                    <input ng-model="ingredient.amount" class="input-mini">
                    <input ng-model="ingredient.amountUnits" class="input-small">
                    <input ng-model="ingredient.ingredientName">
                    <button type="button" class="btn btn-mini" ng-click="removeIngredient($index)">
                        <i class="icon-minus-sign"></i>
                        Delete
                    </button>
                </li>
                <button type="button" class="btn btn-mini" ng-click="addIngredient()">
                    <i class="icon-plus-sign"></i>
                    Add
                </button>
            </ul>
        </div>
    </div>

    <div class="control-group">
        <label class="control-label" for="instructions">Instructions:</label>
        <div class="controls">
            <textarea ng-model="recipe.instructions" class="input-xxxlarge" id="instructions"></textarea>
        </div>
    </div>

    <div class="form-actions">
        <button class="btn btn-primary">Save</button>
        <button type="button" ng-click="remove()" ng-show="!recipe.id" class="btn">
            Delete
        </button>
    </div>
</form>

viewRecipe.html

<h2>{{ recipe.title }}</h2>
<div>{{ recipe.description }}</div>

<h3>Ingredients</h3>
<ul class="unstyled">
    <li ng-repeat="ingredient in recipe.ingredients">
        <span>{{ ingredient.amount }}</span>
        <span>{{ ingredient.amountUnits }}</span>
        <span>{{ ingredient.ingredientName }}</span>
    </li>
</ul>

<h3>Instructions</h3>
<div>{{ recipe.instructions }}</div>

<form ng-submit="edit()" class="form-horizontal">
    <div class="form-actions">
        <button class="btn btn-primary">Edit</button>
    </div>
</form>

运行效果(由于没有编写后台,不少地方会报错甚至不能成功运行):





附:GitHub上下载的工程源代码和用SeaJS组织的工程源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值