1

在上一篇,“AngularJS简单示例”中演示了一个非常简单的使用Angular的小demo,那篇已经太长,原本要介绍的一些内容只好单另开篇了。这些内容,就是如何使用Angular服务。

我们还是基于“AngularJS简单示例”中的示例来改造一下。新的示例,能从Node.js+Express构造的服务器上获取管理菜单。为了实现这个,需要做几部分改造:

  • 服务器提供adminMenu的下载功能,需要修改app.js,处理路由

  • 修改Angular实现的控制器x-controller,使用$http服务从Web服务器下载adminMenu

  • 修改HTML模板,触发下载动作

修改app.js

首先要将app.js文件的编码格式改一下,改成UTF8,因为我在代码里直接硬写入了中文。代码如下:

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

app.get('/adminMenu', function(req, res, next){
  var menus = [
    {
      text: "系统管理",
      enabled: true,
      subMenus:[
        {
          text: "用户管理",
          enabled: true,
          action:"/admin/addUser"
        },
        {
          text: "角色管理",
          enabled: true,
          action:"/role"        
        },
        {
          text: "权限管理",
          enabled: true,
          action:"/access"        
        }
      ]
    },
    {
      text: "内容管理",
      enabled: false,
      subMenus:[
        {
          text: "直播流监控",
          enabled: true,
          action:"/stream-monitor"
        },
        {
          text: "预约管理",
          enabled: true,
          action:"/book-mgr"        
        }
      ]    
    },
    {
      text: "推送管理",
      enabled: true,
      subMenus:[
        {
          text: "推送列表",
          enabled: true,
          action:"/push-list"
        },
        {
          text: "新增推送",
          enabled: false,
          action:"/add-push"        
        }
      ]    
    }    
  ];

  res.status(200).send(menus);  
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

从“app.get(‘/adminMenu’”这行开始,我添加了响应/adminMenu的代码。同时设置了部分菜单项的enabled属性,让从服务器获取的菜单与“Angular简单示例”中来自本地的菜单不同。

触发下载

我修改了admin.html文档,使用了ng-init指令来执行作用域内的init方法。在init方法内,使用$http服务下载管理菜单。

新的html文件被我重命名为admin2.html,依然放在public目录下。相比admin.html,admin2.html只改动了两行代码:

  <body>
    <div class="x-view-full" ng-controller="x-controller" ng-init="init()">
    ......
    <script src="/javascripts/admin2.js"></script>
  </body>

ng-init指令允许我们在当前作用域内执行一个JS表达式。

使用$http服务下载管理菜单

我修改了admin.js,重名为admin2.js,放在public/javascripts目录下。admin2.js内容如下:

angular.module('x-admin', []).
controller('x-controller', ['$scope', '$http', function ($scope, $http) {
  $scope.currentUser="ZhangSan";
  $scope.content = '/welcome.html';

  $scope.menus = [];

  $scope.init = function(){
    $http.get("/adminMenu")
         .success(function(data, status, headers, config){
           console.log("got menus");
           $scope.menus = data;
         })
         .error(function(data, status, headers, config){
           console.log("got menus failed. status - " + status);
         });
  };

  $scope.setContent = function(action){
    console.log(action);
    $scope.content=action;
  };
}]);

我为作用域定义了init方法,供HTML文档内的ng-init指令调用。在init方法内,使用了$http服务来下载adminMenu。

我给success方法提供了回调,当下载成功后,修改作用域的menus属性,把从/adminMenu下载到的json数组直接赋值给menus属性。从Node.js后端到Angular前端,json对json,无需转换,酸爽!

$http的get方法的参数是URI,如示例中的用法,你可以略去域名部分。你也可以使用完整的URL,比如http://localhost:3000/adminMenu,效果是一样一样一样的。

$http服务内部使用了浏览器的XMLHttpRequest(XHR)对象。

好啦,最终,你在浏览器内访问“http://localhost:3000/admin2.html”,效果可能是这样的:

//view-angular-admin2.png

另一种写法

其实呢,这个简单的示例,可以不用ng-init指令,这样更简单,admin2.html与admin.html就只有一点差异:将HTML引用的admin.js修改为admin2.js。然后呢,修改一下admin2.js,直接在控制器的构造函数内开始下载即可。新的代码如下:

angular.module('x-admin', []).
controller('x-controller', ['$scope', '$http', function ($scope, $http) {
  $scope.currentUser="ZhangSan";
  $scope.content = '/welcome.html';
  $scope.menus = [];

  $http.get("http://localhost:3000/adminMenu")
         .success(function(data, status, headers, config){
           console.log("got menus");
           $scope.menus = data;
         })
         .error(function(data, status, headers, config){
           console.log("got menus failed. status - " + status);
         });

  $scope.setContent = function(action){
    console.log(action);
    $scope.content=action;
  };
}]);

更多的Angular服务

Angular提供了很多内置服务,想在控制器内使用的话,在控制器构造函数的参数里直接写上服务的名字,Angular自动会为我们完成依赖注入。

angular.module('x-admin', []).
controller('x-controller', ['$scope', '$http', function ($scope, $http)

上面的代码,x-controller的构造函数依赖scope和http,如果想使用其他的服务,比如$window,可以改成下面这样:

angular.module('x-admin', []).
controller('x-controller', ['$scope', '$http', '$window', function ($scope, $http, $window)

这种写法太繁琐,多输入好些字符,我还是喜欢这样:

controller('x-controller', function ($scope, $http, $interval) {

英雄留步
1.4k 声望18 粉丝