分类目录归档:AngularJS

AngularJS动态应用filter

有的时候我们在动态生成页面内容的时候,需要动态应用filter,这里和大家分享一下方法

假如我们有这样一组数据

[
  {val:"text"},
  {val:"upper text",filter:"uppercase"},
  {val:new Date(),filter:"date",formatter:"yyyy-MM-dd"}
]

数据的值和格式都是动态的
这时候我们需要再写一个filter去动态应用数据的格式

动态应用filter和filter格式的filter

angular.module("app",[])
.filter('use_filter', function ($filter) {
  return function (value, filterName, formatter) {
    return filterName ?
            (formatter ?
                $filter(filterName)(value, formatter) :
                $filter(filterName)(value)) :
            value;
  };
});

使用的时候:

{{item.val| use_filter:item.filter:item.formatter}}

全部代码:

<!DOCTYPE html>
<html ng-app="app">
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
    <script src="http://cdn.staticfile.org/angular.js/1.3.0-beta.13/angular.js"></script>
</head>
<body ng-controller="ctrl">
<div class="container">
    <ul>
        <li ng-repeat="item in data">
            <span>{{item| json}}</span>{{item.val| use_filter:item.filter:item.formatter}}
        </li>
    </ul>
</div>
<script>
angular.module("app",[])
.controller("ctrl",function($scope){
    $scope.data = [
        {val:"text"},
        {val:"upper text",filter:"uppercase"},
        {val:new Date(),filter:"date",formatter:"yyyy-MM-dd"}
    ];
})
.filter('use_filter', function ($filter) {
    return function (value, filterName, formatter) {
        return filterName ?
                (formatter ?
                    $filter(filterName)(value, formatter) :
                    $filter(filterName)(value)) :
                value;
    };
});
</script>
</body>
</html>

直接运行代码:

提示:你可以先修改部分代码再运行。

使用angularjs directive生成api方法供其他地方调用angularjs directive expose api

有些时候我们需要directive生成api,可以在其他地方(controller)调用
image1419911269
下面介绍下简单的步骤:

使用directive的双向绑定绑定controller里的变量

html:
<div expose="exposedApi"></div>
js:

directive('expose',function(){
  return {
    restrict: "A",
    scope: {
      api: "=expose"
    }
  };

这个时候controller离的exposedApi变量和directive里的api是双向绑定的

给directive里的api增加可调用的方法

directive('expose',function(){
  return {
    restrict: "A",
    scope: {
      api: "=expose"
    },
    controller: function($scope){
      $scope.number = 0;
      $scope.api={
        count:function(){
          $scope.number ++;
        }
      };
    },
    template: '<div class="well">' +
              '<p>count: {{number}}</p>' +
              '</div>'
  };

调用directive里的方法

controller("ctrl",function($scope){
  $scope.count = function(){
    $scope.exposedApi.count();
  };
})

Demo:

http://shengoo.github.io/angularjs-practice

完整代码:

<!DOCTYPE html>
<html ng-app="app">
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.css" />
  <script src="../bower_components/angular/angular.js"></script>
</head>
<body ng-controller="ctrl">
<div class="container">
<div expose="exposedApi"></div>
<a ng-click="count()" class="btn btn-primary">click</a>
<div expose="exposedApi2"></div>
<a ng-click="count2()" class="btn btn-primary">click</a>
</div>
<script>
angular.module("app",[])
.controller("ctrl",function($scope){
  $scope.count = function(){
    $scope.exposedApi.count();
  };
  $scope.count2 = function(){
    $scope.exposedApi2.count();
  };
})
.directive('expose',function(){
  return {
    restrict: "A",
    scope: {
      api: "=expose"
    },
    controller: function($scope){
      $scope.number = 0;
      $scope.api={
        count:function(){
          $scope.number ++;
        }
      };
    },
    template: '<div class="well">' +
              '<p>count: {{number}}</p>' +
              '</div>'
  };
})
</script>
</body>
</html>

angularjs directive

在AngularJS中,Dom操作应该在directive里进行,而不应该在controllers, services或者其他任何地方。

directives命名

  • 使用不重复的前缀
    • 防止和其他人重复
    • 易读
  • 不要用ng-作为你的directive的前缀
  • 常见情况:两个单词
    • AngularUI project 用的是 “ui-“

什么时候用directives?

  • 可复用的HTML控件
    <my-widget>

  • 可复用的HTML行为
    <div ng-click="...">

  • 包装一个jQuery插件
    <div ui-date></div>

  • 你需要和DOM交互的绝大多数情况

创建一个directive

先给你的directive创建一个module

angular.module('MyDirectives',[]);

在你的app里加入directive module的依赖

angular.module('app',['MyDirectives']);

注册你的directive

angular.module('MyDirectives')
.directive('myDirective', function(){
  // TODO:
});

在HTML里使用你的directive

<div my-directive>...</div>

Restrict参数

‘A’

attributes
<div my-directive></div>

‘E’

element
<my-directive></my-directive

‘C’ ‘M’

rarely used
‘C’: classes ‘M’ : comments

组合

restrict: 'AE'

隔离的scope

directive默认是没有scope的,我们可以给它一个scope

scope: {
  someParam: '='
}

或者
scope: true
这个scope不会继承其他scope

scope参数

scope参数是从HTML的属性(attribute)传进来的

scope: {
  param1: '=', // 双向绑定(directive和controller)
  param2: '@', // 单向绑定
  param3: '&'  // 单向行为
}
<div my-directive
  param1="someVariable"
  param2="My name is {{name}}"
  param3="doSth()"
>

$digest already in progress 解决办法

常见原因

除了简单的不正确调用 $apply$digest,有些情况下,即使没有犯错,也有可能得到这个错误。

可能出错的代码

function MyController($scope, thirdPartyComponent) {
  thirdPartyComponent.getData(function(someData) {
    $scope.$apply(function() {
      $scope.someData = someData;
    });
  });
}

改成这样就可以了

function MyController($scope, thirdPartyComponent) {
  thirdPartyComponent.getData(function(someData) {
    $timeout(function() {
      $scope.someData = someData;
    }, 0);
  });
}

使用AngularJS service作为KendoUI的datasource

angular.module("app", ["kendo.directives"])
.controller("news", function($scope,newsService) {
  var dataSource = new kendo.data.DataSource({
    transport: {
      read: dataSourceRead
    }
  });
  function dataSourceRead(options){
    //todo: show loading
    newsService.getByCategory($scope.selectedCategory.value)
      .then(
        function(response){
          options.success(response);
          //todo: hide loading
        },
        function(response){
          options.error(response);
          //todo: handle errors.
        });
  }
  $scope.newsListViewOptions = {
    dataSource: dataSource
  };
})
.service('newsService', function($q, $http) {
  this.getByCategory = function(category){
    var url = "your url";
    var request = $http({
      method: "jsonp",
      url: url
    });
    return( request.then( handleSuccess, handleError ) );
  };
  function handleError( response ) {
    //if no message return from server
    if (
      ! angular.isObject( response.data ) ||
      ! response.data.message
      ) {
      return( $q.reject( "An unknown error occurred." ) );
    }
    return( $q.reject( response.data.message ) );
  }
  function handleSuccess( response ) {
    return( response.data );
  }
});

angularjs service factory provider 区别

Services
Syntax: module.service( ‘serviceName’, function );
Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService().
Factories
Syntax: module.factory( ‘factoryName’, function );
Result: When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factory.
Providers
Syntax: module.provider( ‘providerName’, function );
Result: When declaring providerName as an injectable argument you will be provided with ProviderFunction().$get(). The constructor function is instantiated before the $get method is called – ProviderFunction is the function reference passed to module.provider.

angularjs星级评分 star rating directive

directive

var app = angular.module("app", []);
app.controller('ctrl',function($scope){
  $scope.max = 5;
  $scope.ratingVal = 2;
  $scope.readonly = false;
  $scope.onHover = function(val){
    $scope.hoverVal = val;
  };
  $scope.onLeave = function(){
    $scope.hoverVal = null;
  }
  $scope.onChange = function(val){
    $scope.ratingVal = val;
  }
});
app.directive('star', function () {
  return {
    template: '<ul class="rating" ng-mouseleave="leave()">' +
        '<li ng-repeat="star in stars" ng-class="star" ng-click="click($index + 1)" ng-mouseover="over($index + 1)">' +
        '\u2605' +
        '</li>' +
        '</ul>',
    scope: {
      ratingValue: '=',
      max: '=',
      readonly: '@',
      onHover: '=',
      onLeave: '='
    },
    controller: function($scope){
      $scope.ratingValue = $scope.ratingValue || 0;
      $scope.max = $scope.max || 5;
      $scope.click = function(val){
        if ($scope.readonly && $scope.readonly === 'true') {
          return;
        }
        $scope.ratingValue = val;
      };
      $scope.over = function(val){
        $scope.onHover(val);
      };
      $scope.leave = function(){
        $scope.onLeave();
      }
    },
    link: function (scope, elem, attrs) {
      elem.css("text-align", "center");
      var updateStars = function () {
        scope.stars = [];
        for (var i = 0; i < scope.max; i++) {
          scope.stars.push({
            filled: i < scope.ratingValue
          });
        }
      };
      updateStars();
      scope.$watch('ratingValue', function (oldVal, newVal) {
        if (newVal) {
          updateStars();
        }
      });
      scope.$watch('max', function (oldVal, newVal) {
        if (newVal) {
          updateStars();
        }
      });
    }
  };
});

css:

.rating {
  color: #a9a9a9;
  margin: 0;
  padding: 0;
}
ul.rating {
  display: inline-block;
}
.rating li {
  list-style-type: none;
  display: inline-block;
  padding: 1px;
  text-align: center;
  font-weight: bold;
  cursor: pointer;
}
.rating .filled {
  color: #ffee33;
}

html:

<div ng-app="app">
<div class="well" ng-controller="ctrl">
  <div star rating-value="ratingVal" max="max" on-hover="onHover" on-leave="onLeave" readonly="{{readonly}}"></div>
  <div>
    Max: <input type="number" name="input" ng-model="max" min="0" max="99" required>
    <p>current value: {{ratingVal}}</p>
    <p>hover on : {{hoverVal?hoverVal:"none"}}</p>
    <p>readonly : <input type="checkbox"
       ng-model="readonly"></p>
  </div>
</div>
</div>

github page

http://shengoo.github.io/angularjs-practice/directive/star/star.html

jsfiddle:

code pen:

See the Pen angularjs star rating directive by Qing Sheng (@shengoo) on CodePen.