Having trouble with ng-class not updating properly when using setTimeout in Angular?

I am encountering an issue with my 'highlightBookmark' function that is supposed to change the background color of a list item after 2 seconds. However, it is not working as expected! The background color only changes when the function is called by a click event and not automatically after the specified time has passed.

Below is the code snippet:

Controller.js

//markers
$scope.markers = [
    {
        time: 9.5,
        text: "Bookmark 1",
        class: false
    },
    {
        time: 106,
        text: "Bookmark 2",
        class: false
    }
]

$scope.currentBookmark = -1;

function highlightBookmark(index) {
    $scope.markers[index].class = true;
}

var interval = setInterval(checkTime, 100);

function checkTime(){
    if(Math.floor(player.currentTime()) == 2){
        highlightBookmark(1)
        clearInterval(interval);
    }
}

$scope.jumpTo = function (index) {
    highlightBookmark(index);
}

The 'highlightBookmark' function takes an integer as input, finds the object at that position, and updates the 'class' property to true. For example, passing the number 1 to the function will update the 'class' property of the object at index 2 to true.

Although the 'highlightBookmark' function is being called after 2 seconds, the class does not get updated, resulting in no change in background color.

When I call the function using a click event, it works perfectly.

HTML file

<ul id="bookmarkList">
    <li ng-repeat="bookmark in markers" ng-class="{'active': bookmark.class}" ng-click="jumpTo($index)">{{bookmark.text}}</li>
</ul>

The list item in the HTML file has the ng-class property that should be changed after 2 seconds.

You can view a similar code on Codepen where a button's color changes upon click but doesn't change after setTimeout, even though the method is called.

https://codepen.io/Octtavius/pen/wgzORv

I would appreciate any help in resolving this simple issue.

Answer №1

If you're struggling with the vanilla setInterval function not updating scope variables, consider using the $interval API provided by Angular instead:

var interval = $interval(checkTime, 100);

function checkTime(){
    if(Math.floor(player.currentTime()) == 2){
        highlightBookmark(1)
        interval.cancel();
    }
}
  1. Note that clearInterval(interval) should be changed to interval.cancel()
  2. Don't forget to inject it as a dependency.
  3. A valid point made by charlietfl: Remember to cancel the interval if the scope is destroyed.

Insert this code snippet into your controller:

$scope.$on("$destroy", function( event ) {
    interval.cancel( timer );
});

For more information, visit: https://docs.angularjs.org/api/ng/service/$interval

Answer №2

setInterval and setTimeout don't operate within the Angular digest cycle, making them difficult for Angular to track.

An alternative is to utilize the $timeout service in your controller, which provides the same timeout functionality while remaining under Angular's observation.

Answer №3

It is recommended to use angular $timeout over setInterval or setTimeout.

Reasons for using $timeout:

  1. These functions do not trigger a $digest on the $scope variables;
  2. $timeout consumes less memory while achieving the same result as $interval.

This is how your controller section will be structured:

//markers
$scope.markers = [
    {
        time: 9.5,
        text: "Bookmark 1",
        class: false
    },
    {
        time: 106,
        text: "Bookmark 2",
        class: false
    }
]

$scope.currentBookmark = -1;

function highlightBookmark(index) {
    $scope.markers[index].class = true;
}

$timeout(checkTime, 2000);

function checkTime(){
    highlightBookmark(1);
}

$scope.jumpTo = function (index) {
    highlightBookmark(index);
}

Do not forget to inject the $timeout as a dependency in your controller.

P.S.

The provided code will set a default bookmark after 2 seconds. For further improvements, additional details about the player's behavior are required. Provide more context so that adjustments can be made accordingly.

Consider implementing "controller as" approach. Refer to John Papa's article on this topic for more insights:

If you wish to toggle background on click event, utilize the following code snippet which ensures proper handling of multiple li elements:


<div ng-app="classApp" ng-controller="classCtrl">
   <ul id = "bookmarkList">
    <li ng-repeat="bookmark in markers" ng-class="{'active': selectedMarker === bookmark}" ng-click="jumpTo(bookmark)">{{bookmark.text}}</li>
   </ul>
</div>

$scope.selectedMarker = null;

function highlightBookmark(marker) {
   $scope.selectedMarker = marker;
}

$timeout(checkTime, 2000);

function checkTime(){
   highlightBookmark($scope.markers[0])
}

$scope.jumpTo = function (marker) {
   highlightBookmark(marker);
}

See you later!

Answer №4

let myApp = angular.module('myApp', []);

myApp.controller('myCtrl', function ($scope, $timeout) {
    $scope.isClicked = false;
    $scope.clickButton = function () {
        $scope.isClicked = !$scope.isClicked;
    }

    function updateTime() {
        $scope.isClicked = !$scope.isClicked;
    }

    $timeout(updateTime, 2000)
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the reason behind BehatMinkElementNodeElement:setValue function removing dashes in the input value?

I am currently utilizing Behat version 3.0.15, Selenium version 3.4, and PhantomJS as the browser. In my Behat custom step, I have code to set the value of an input date field with a single line: $element->setValue('1999-01-01'); However, u ...

Having trouble getting my list items to display on individual lines within the foreach loop. It just doesn't seem to be working as expected

In the event listener, I need to ensure that my list items within the forEach loop are not displaying on separate lines. This issue is causing a problem in a lengthy section of code. The goal is to update questions when an answer is clicked from a list. B ...

Manipulate the DOM elements within the ng-repeat directive

Hello, I am currently new to AngularJS and have just begun learning how to create directives. While working on a sample project, I encountered an issue with accessing DOM elements rendered inside my directive. Some elements were not accessible in the link ...

JavaScript React: A notification is appearing in the console indicating that my React Hook useEffect is missing dependencies

My browser console is showing the following message: src/App.js Line 41:6: React Hook useEffect has missing dependencies: 'handleBonusItem' and 'handleDiscount'. To resolve this, you need to include them in the dependency array or remov ...

Utilizing the ng-if directive to choose the second element within an iteration of an ng-repeat loop

I am currently working on a project where I need to organize and group content by day. While the grouping function is working fine, I am facing an issue with treating the first two items in the loop differently from the rest. I have experimented with using ...

Automatically refresh a table within a webpage with updated database information without the need to manually refresh the

I'm a beginner in PHP and AJAX. The issue I am currently encountering is displaying a table on a JSP page and wanting to auto-update the table without refreshing the page every 10 seconds. I retrieve values from a database using a PHP page Below is t ...

Using JavaScript to Retrieve Image Sources

function validate(form) { while ($('#img').attr('src')=="../static/img/placeholder.png") { return false; } return true; } ^I'm having trouble with this code. I want my form to prevent submission as long as ...

Switching the Visibility of Bootstrap Navbar Collapse when Changing Views using AngularJS

Currently, I am facing an issue with the Bootstrap ui-module and AngularJS integration. The problem arises in the mobile view when a user switches views, as the .navbar-collapse remains open instead of collapsing. Despite being new to Angular, I have start ...

Tips for locking the table header and left column in place without any border flickering

I have been tackling the task of organizing table data recently. I managed to fix the table header and left column using jQuery, which is working fine. However, I noticed that when I scroll through the table, the borders start flickering. When I set the ba ...

Scope of the variable not defined within the ajax callback

function verifyDeleteFacilitator(facilitatorId, handleData) { var request = $.ajax({ type: 'GET', url: urls.verifydeletefacilitator, data:{facilitatorId: facilitatorId} }).done(function (response) { return handleData(response); }) ...

What is the best way to reorganize an item in JavaScript?

I am looking to organize a list of various locations based on their respective cities: [ { "id": 1, "name": "Location 1", "city": { "id": 7, "name": "Phoenix", } }, { "id": 2, "name": "Location 2", "city": { ...

Retrieving Data with AJAX: Submitting Data and Retrieving Response

I need help implementing an AJAX feature for the following process: When a visitor clicks a button, I want to display a spinning/loading image using AJAX. AJAX will then access URL 1 http://www.mywebsite.com/url1.php to retrieve a random code, such a ...

Learn the process of creating various themes with Tailwind CSS

When exploring Tailwind CSS, it appears that specific colors need to be specified in classes like this: <div class="bg-yellow-200 dark:bg-gray-800"></div> However, I am interested in offering 10 different themes for users to choose f ...

Transform improperly formatted strings into a date data type

I need help converting this string to a date type in Typescript for sorting purposes: 31/10/2017 18:12:02 Using new Date() is not working (it returns Invalid Date), even when trying like this : let date = moment(item1.sendedOn.toString()).format(&apos ...

What are the steps to creating a dynamic, layered column design using HTML?

I'm looking to create a layout that resembles the one on www.PInterest.com, featuring varying numbers of columns depending on the browser width (responsive design). My challenge lies in stacking the boxes vertically with different heights, without let ...

I am currently in the process of testing my Angular controller using Jasmine, however, encountering an issue with the error message: [$injector:modulerr]

Here is the code snippet from my Angular project: app.js code: (function () { 'use strict'; var app = angular.module('actorsDetails', [ // Angular modules 'ngResource', // 3rd Party Modules ...

Transforming a JSON object property value from an array into a string using JavaScript

I am facing an issue with an API call I am using, as it is sending objects with a single property that contains an array value (seen in the keys property in the response below). However, I need to work with nested arrays in order to utilize the outputted v ...

In React, the `context` is consistently an empty object

I am facing an issue while trying to establish a context in my React App. For some reason, I am unable to access context from the children components. Here is the parent component: import React from 'react' import MenuBar from './MenuBar.js ...

Merge a handful of regex patterns

In search for a way to modify a string using regex, I experimented with various approaches and managed to come close. Here are some examples of different scenarios and the expected outcomes: case A: "Schoenen US 30 / " should be transformed to -> "30" ...

Try implementing toggleClass() in the accordion feature rather than addClass() and removeClass()

Hey there! I've implemented accordion functionality using the addClass() and removeClass() methods. Here's a breakdown of what I did: <div class="container"> <div class="functionality">Accordion</div> <ul class="acco ...