5
\$\begingroup\$

This directive works fine but I have the feeling that I'm not doing it the "angular way" with .attr('hide', 'true'). Is there a better way to show or hide elements from a directive?

app.directive('myRandomshow', function() {
 // Show a random element from child elements
 function randomIntFromInterval(min, max) {
 return Math.floor(Math.random() * (max - min + 1) + min);
 }
 return {
 link: function(scope, element) {
 // Ensure everything is initialy hidden
 element.children().attr('hide', 'true');
 scope.$on('event::event', function() {
 // Show result
 element.children().attr('hide', 'true');
 element.children().eq(randomIntFromInterval(2, element.children().length - 1)).removeAttr('hide');
 });
 }
 };
});
Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
asked May 18, 2015 at 13:11
\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

Correct me if this is incorrect but it appears that this code utilizes jQuery methods like .children(), .attr(), .eq() and .removeAttr(). Many would argue that this is far from the "angularJS way" of developing such code.

As this answer explains:

AngularJS is a framework that handles "data binding" for you, meaning it will (and should) take charge of keeping your model (e.g. $scope) and view (the markup) in synch. You should usually not interfere with this behavior, unless there is a very specific reason to do so. A quite lengthy but interesting read on this and related topics can be found in this answer (which incidentally was answered to a question about when it is okay to use jQuery yourself).

Long story short: don't update the DOM inside your controller / scope.

Instead of updating the DOM using jQuery methods, the ngHide directive could be used. In order to do that from the directive one might need to utilize properties stored in the controller that would control the values used for the ng-hide attribute on each child element.

A demonstration of this is below. There are three buttons labeled 1, 2 and 3 and all are hidden by default. Clicking the button above them will randomly select one button to show (and of course hide the others, similar to the original code).

angular.module('sampleDirective', [])
 .controller('Controller', ['$scope', function($scope) {
 $scope.children = Array(3).fill(0).map((value, id) => ({
 id: id + 1,
 hidden: false
 }));
 }])
 .directive('myRandomshow', function() {
 // Show a random element from child elements
 function randomIntFromInterval(min, max) {
 return Math.floor(Math.random() * (max - min + 1) + min);
 }
 return {
 link: function(scope, element) {
 scope.children.forEach(child => child.hidden = true);
 scope.$on('event::event', function() {
 // Show result
 const indexToShow = randomIntFromInterval(1, scope.children.length);
 scope.children.forEach((child, index) => child.hidden = (index + 1) != indexToShow);
 });
 }
 };
 });
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="sampleDirective">
 <div ng-controller="Controller">
 <button ng-click="$emit('event::event')">Show a randomly selected child</button>
 <div my-randomshow>
 <button ng-repeat="(key, child) in children track by key" ng-hide="child.hidden">{{ child.id }}</button>
 </div>
 </div>
</div>

answered Sep 12, 2022 at 22:21
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.