如何定义一个包含方法的角度指令,可以通过`ng-click`调用?

时间:2022-06-07 10:09:48

I want to define a directive which will show the first child which contains a button at first. If we click on the button, the second child will be replace the first one.

我想定义一个指令,它将首先显示包含按钮的第一个子节点。如果我们点击按钮,第二个孩子将替换第一个孩子。

HTML:

HTML:

<div show-more>
  <div>short <button ng-click="showMore()">click-me to show more</button></div>
  <div>full</div>
</div>

Angular:

角度:

angular.module("app", [])
.directive("showMore", function() {
  return {
    restrict: 'A',
    scope: {},
    link: function(scope, element, attrs) {

      var children = element.children();
      var short = children[0];
      var full = children[1];

      element.empty().append(short);

      scope.showMore = function() {
        element.empty().append(full);
      };

    }
  };
});

The problem is that when I click the button, there is nothing happen. I tried a lot but still not work.

问题是当我点击按钮时,没有任何事情发生。我尝试了很多但仍然无法工作。

You can see a live demo here: http://jsbin.com/rugov/2/edit

你可以在这里看到现场演示:http://jsbin.com/rugov/2/edit

How to fix it?

怎么解决?

3 个解决方案

#1


1  

Since you are changing the DOM of the element of your directive, you will need to re-$compile the element, like this:

由于您要更改指令元素的DOM,因此需要重新编译元素,如下所示:

.directive("showMore", function($compile) {
  return {
    restrict: 'A',
    scope: {},
    link: function(scope, element, attrs) {

      var children = element.children();
      var short = children[0];
      var full = children[1];

      element.empty().append(short);
      $compile(element.contents())(scope);

      scope.showMore = function() {
        element.empty().append(full);
      };

    }
  };
});

Working Example

#2


1  

The problem is that your directive creates new isolated scope, but ng-click directive is placed on element, that is in another scope. I would implement your requirements via 2 directive, one depends from another.

问题是你的指令创建了新的隔离范围,但是ng-click指令放在元素上,即另一个范围内。我将通过2指令实现您的要求,一个取决于另一个。

angular.module("app", [])
  .directive("showMoreWrapper", function() {
    return {
      restrict: 'A',
      scope: {},
      controller: function($element) {
        this.showMore = function() {
          var children = $element.children();
          children.eq(0).hide();
          children.eq(1).show();
        };
      },
      link: function(scope, element, attrs) {
        var children = element.children();
        children.eq(1).hide();
      }
    };
  })
  .directive("showMore", function() {
    return {
      restrict: 'A',
      require: '^showMoreWrapper',
      link: function(scope, element, attrs, showMoreWrapper) {
        element.on('click', showMoreWrapper.showMore);
      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div show-more-wrapper>
    <div>short
      <button show-more>click-me to show more</button>
    </div>
    <div>full</div>
  </div>
</div>

#3


0  

I would take a custom component approach

我会采用自定义组件方法

angular.module("app", [])
.directive("showMore", function() {
  return {
    restrict: 'E',
    scope: {},
    transclude: true,
    template: '<button ng-click="toggle()">{{title}}</button><div ng-transclude></div>',
    controller: function($scope) {
      var self = this;
      $scope.title = "Show More";
      
      $scope.toggle = function() { 
        self.short.show = !self.short.show;
        self.full.show = !self.full.show;
        $scope.title = self.short.show ? "Show More" : "Show Less";
      };
      this.addShort = function(short) {
        self.short = short;
      };
      this.addFull = function(full) {
        self.full = full;
      };
    }
  };
})
.directive("short", function() {
  return {
    restrict: 'E',
    scope: {},
    require: '^showMore',
    transclude: true,
    template: '<div ng-if="show" ng-transclude></div>',
    link: function(scope, element, attrs, showMoreCtrl) {
      scope.show = true;
      showMoreCtrl.addShort(scope);
    }
  };
})
.directive("full", function() {
  return {
    restrict: 'E',
    scope: {},
    require: '^showMore',
    transclude: true,
    template: '<div ng-if="show" ng-transclude></div>',
    link: function(scope, element, attrs, showMoreCtrl) {
      scope.show = false;
      showMoreCtrl.addFull(scope);
    }
  };
});
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<div ng-app="app">
      <show-more>
        <short>short</short>
        <full>full</full>
      </show-more>
</div>

#1


1  

Since you are changing the DOM of the element of your directive, you will need to re-$compile the element, like this:

由于您要更改指令元素的DOM,因此需要重新编译元素,如下所示:

.directive("showMore", function($compile) {
  return {
    restrict: 'A',
    scope: {},
    link: function(scope, element, attrs) {

      var children = element.children();
      var short = children[0];
      var full = children[1];

      element.empty().append(short);
      $compile(element.contents())(scope);

      scope.showMore = function() {
        element.empty().append(full);
      };

    }
  };
});

Working Example

#2


1  

The problem is that your directive creates new isolated scope, but ng-click directive is placed on element, that is in another scope. I would implement your requirements via 2 directive, one depends from another.

问题是你的指令创建了新的隔离范围,但是ng-click指令放在元素上,即另一个范围内。我将通过2指令实现您的要求,一个取决于另一个。

angular.module("app", [])
  .directive("showMoreWrapper", function() {
    return {
      restrict: 'A',
      scope: {},
      controller: function($element) {
        this.showMore = function() {
          var children = $element.children();
          children.eq(0).hide();
          children.eq(1).show();
        };
      },
      link: function(scope, element, attrs) {
        var children = element.children();
        children.eq(1).hide();
      }
    };
  })
  .directive("showMore", function() {
    return {
      restrict: 'A',
      require: '^showMoreWrapper',
      link: function(scope, element, attrs, showMoreWrapper) {
        element.on('click', showMoreWrapper.showMore);
      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div show-more-wrapper>
    <div>short
      <button show-more>click-me to show more</button>
    </div>
    <div>full</div>
  </div>
</div>

#3


0  

I would take a custom component approach

我会采用自定义组件方法

angular.module("app", [])
.directive("showMore", function() {
  return {
    restrict: 'E',
    scope: {},
    transclude: true,
    template: '<button ng-click="toggle()">{{title}}</button><div ng-transclude></div>',
    controller: function($scope) {
      var self = this;
      $scope.title = "Show More";
      
      $scope.toggle = function() { 
        self.short.show = !self.short.show;
        self.full.show = !self.full.show;
        $scope.title = self.short.show ? "Show More" : "Show Less";
      };
      this.addShort = function(short) {
        self.short = short;
      };
      this.addFull = function(full) {
        self.full = full;
      };
    }
  };
})
.directive("short", function() {
  return {
    restrict: 'E',
    scope: {},
    require: '^showMore',
    transclude: true,
    template: '<div ng-if="show" ng-transclude></div>',
    link: function(scope, element, attrs, showMoreCtrl) {
      scope.show = true;
      showMoreCtrl.addShort(scope);
    }
  };
})
.directive("full", function() {
  return {
    restrict: 'E',
    scope: {},
    require: '^showMore',
    transclude: true,
    template: '<div ng-if="show" ng-transclude></div>',
    link: function(scope, element, attrs, showMoreCtrl) {
      scope.show = false;
      showMoreCtrl.addFull(scope);
    }
  };
});
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<div ng-app="app">
      <show-more>
        <short>short</short>
        <full>full</full>
      </show-more>
</div>