1

I'm new to this directive in AngularJS and would need some help to get this javascript function to work. It was okay when I just used plain JavaScript outside the angular directive. But now I have hit some problems.

It's okay down to the function navigate and I get an error that:

removeClass is not a function

It works with addClass so I don't understand why remove doesn't work here.

<ol class="content">
    <li>
        "{{ myData.quotes[0].quote }}"
        <br /> <div class="quoteLine"></div> <span class="boldText"> {{ myData.quotes[0].person }} </span>
    </li>

    <li>
        "{{ myData.quotes[1].quote }}"
        <br /> 
        <div class="quoteLine"></div> <span class="boldText"> {{ myData.quotes[1].person }} </span>
    </li>
</ol>
app.directive('myCarousel', function () {
    return {
        link: function ($scope, $element) {
            var next = $element.find('.next');
            var prev = $element.find('.prev');
            var items = $element.find('.content li');
            var counter = 0;
            var amount = items.length;
            var current = items[0];

            $element.addClass('active')

            function navigate (direction) {
                current.removeClass('current')
                counter = counter + direction

          if (direction === -1 && counter < 0) { 
            counter = amount - 1
          }

          if (direction === 1 && !items[counter]) { 
            counter = 0
          }

              current = items[counter]
              current.addClass('current')
            }

            // go to next quote
            next.on('click', function (ev) {
              navigate(1)
            })

            // go back to previous quote
            prev.on('click', function (ev) {
              navigate(-1)
            })

            navigate(0)
        }
    }
})
georgeawg
  • 48,608
  • 13
  • 72
  • 95
Lacon
  • 105
  • 3
  • 11
  • Have you tried to log `current`? Maybe there's a mistake somewhere and `.find('.content li')` returns an empty list? – Kaddath Apr 25 '18 at 12:55
  • var items = $element.find('.content li'); this is probably filled wrongly . Inspect your genereted html and use the dev tools of browser to check if your selector is correct – Panos K Apr 25 '18 at 13:06
  • mmmm could it be you are invoking `current.removeClass('current')` before `current.addClass('current')` ? how can you remove what there isnt? – Leandro Apr 25 '18 at 13:14
  • Possible duplicate of [How to add/remove a class in JavaScript?](https://stackoverflow.com/a/28344281/5535245). – georgeawg Apr 25 '18 at 14:40

3 Answers3

1

The removeClass method is a jQuery or jQLite method. The raw element needs to be wrapped:

var items = $element.find('.content li');
var counter = 0;
var amount = items.length;
var current = items[0];

$element.addClass('active')

function navigate (direction) {
    ̶c̶u̶r̶r̶e̶n̶t̶.̶r̶e̶m̶o̶v̶e̶C̶l̶a̶s̶s̶(̶'̶c̶u̶r̶r̶e̶n̶t̶'̶)̶
    //WRAP raw element
    var $current = angular.element(current);
    $current.removeClass('current')
    counter = counter + direction

For more information, see AngularJS angular.element API Reference - jQLite.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
0

Firstly, the current variable is not a jQLite instance, so in order to use removeClass you have to wrap it with jQLite like so:

angular.element(current).removeClass('current')

Sencondly, the variable items is probably empty because $element.find('.content li') can't be used like that if you are using pure jQLite, because if so, the method find would be limited to look up by tag name only. So if you need to use that complex selector, you should try $element[0].querySelectorAll('.content li') or use old school getElementsByClassName.

lenilsondc
  • 9,590
  • 2
  • 25
  • 40
0

You could, if you wanted, rather than use Javascript to manipulate the classes to show and hide your text quotes, pass in your quotes to your directive and have the directive itself figure out which to show and which not to (might be a more "angular way" of doing things).

For example, something like the following directive:

app.directive('myCarousel', function () {
return {
    scope: {
    quotes: '<'
    },
    templateUrl: 'myCarousel.html',
    controllerAs: 'ctrl',
    controller: function($scope) {
    let ctrl = this;

    ctrl.previousQuote = previousQuote;
    ctrl.nextQuote = nextQuote;

    let selectedQuoteId = 0;
    ctrl.selectedQuote = $scope.quotes[selectedQuoteId];

    function previousQuote() {
        if (selectedQuoteId !== 0) {
        selectedQuoteId--;
        ctrl.selectedQuote = $scope.quotes[selectedQuoteId];  
        }
    }

    function nextQuote() {
        if (selectedQuoteId + 1 < $scope.quotes.length) {
        selectedQuoteId++;
        ctrl.selectedQuote = $scope.quotes[selectedQuoteId];  
        }
    }
    }
}
});

And the myCarousel.html template:

<div>
<ol class="content">
<li>
    "{{ctrl.selectedQuote.quote}}"
    <br /> <div class="quoteLine"></div> <span class="boldText"> {{ctrl.selectedQuote.person}} </span>
</li>
</ol>
<button ng-click="ctrl.previousQuote()"><</button>
<button ng-click="ctrl.nextQuote()">></button>
</div>

This is figuring out which quote object is currently selected (selectedQuote) and then outputs it within the template.

Then you can just pass in your quote data from anywhere.

If you're interested, you can view it in action at this Plunker: https://plnkr.co/edit/vA80sTdjwClWvF4T4dbd

Christian
  • 51
  • 2