Troubleshooting $digest problems with AngularJS and the selectize directive

I am encountering difficulties when utilizing the watch function within a directive in conjunction with a third-party plugin named selectize.

Despite researching extensively about $digest and $watch, I am still facing issues.

Although my example below is functioning, I am striving to avoid the $digest already in progress errors.

There might be a more efficient approach to tackle this problem, but I am uncertain about it.

Check out the plunker link for reference: http://plnkr.co/edit/3JjTsEU2BlxPWHtw6HaW?p=preview

app.directive('selectize', function($parse) {
return {
  restrict: 'A',
  require: ['ngModel'],
  scope: {
    ngModel: '=',
    options: '='
  },
  link: function(scope, el, attrs) {

    var $select = el.selectize({
      valueField: 'id',
      labelField: 'name'
    });

    var selectize = $select[0].selectize;

    // add options
    angular.forEach('options', function(tag) {
      selectize.addOption(tag);
    });

    scope.$watchCollection('options', function(newTags, oldTags) {

      // why are these the same objects?
      console.log('newTags', newTags);
      console.log('oldTags', oldTags);

      if (newTags !== oldTags) {
        // clear options
        selectize.clear();
        selectize.clearOptions();

        // add options
        angular.forEach(newTags, function(tag) {
          selectize.addOption(tag);
        });
      }

    });

    // if value changes without selecting an option,
    // set the option to the new model val
    scope.$watch('ngModel', function(val) {
      console.log('val', val);
      // selectize.setValue(val);
    });
  }
};
});

Answer №1

To ensure smooth execution of the 3rd party calls, consider encapsulating them within a $timeout function like so:

$timeout(function() {
    // Clearing options
    selectize.clear();
    selectize.clearOptions();

    // Adding new options
    angular.forEach(newTags, function(tag) {
      selectize.addOption(tag);
    });

}, 0);

Remember to inject $timeout into your code.

By using a timeout value of zero (omitting the value defaults to 0), it is highly likely that the code will execute during the subsequent digest loop, thereby preventing any ongoing errors. If my understanding is correct, this method can effectively resolve issues with digest already in progress errors when incorporating certain third-party JavaScript libraries (such as tinyMce). Feel free to confirm or provide additional insights on this matter. For further details, refer to betaorbust's explanation in the following Stack Overflow post: AngularJS : Prevent error $digest already in progress when calling $scope.$apply()

Answer №2

I recently developed a custom directive for Selectize that enables 2-way binding between the model and options. I also incorporated the use of $timeout to ensure proper functionality.

For more information, you can check out the code on GitHub: https://github.com/machineboy2045/angular-selectize

You can also view a demo of the directive in action on Plunker: http://plnkr.co/edit/twGAfU?p=preview

Below are the key components of the directive. Note that some additional features have been omitted from this excerpt:

app.directive('selectize', function($timeout) {
  return {
    restrict: 'A',
    require: '^ngModel',
    link: function(scope, element, attrs, ngModel) {

      var config = scope.$eval(attrs.selectize);
      config.options = scope.$eval(attrs.options) || [];
      element.selectize(config);
      var selectize = element[0].selectize;

      selectize.on('option_add', refreshAngularOptions);
      scope.$watch(function(){ return ngModel.$modelValue}, refreshSelectize, true)

      function refreshAngularOptions(value, data) {
        config.options = selectize.options;
      }

      function createOption(opt){
        var newOpt = {};
        newOpt[selectize.settings.valueField] = opt;
        newOpt[selectize.settings.labelField] = opt;
        selectize.addOption(newOpt);
      }

      function refreshSelectize(value){
        $timeout(function(){
          if(angular.isArray(value))
            angular.forEach(value, createOption);
          else
            createOption(value);

          selectize.refreshOptions(false);
          selectize.setValue(value); 
        })
      }
    }
  };
});

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

Automatically scrolling through a nested list in ReactJs

I have a chat list integrated into my web application. The entire webpage is scrollable, as shown in the image at the bottom. I would like the messages list to automatically scroll to the bottom whenever a new message arrives. To achieve this, I created a ...

Initiate a click event on an anchor element with the reference of "a href"

I'm currently facing an issue with clicking a href element on my HTML website. The click event doesn't seem to be triggered. CODE: HTML CODE: <div class="button" id="info" ></div> <ul id="game-options"> <li><a ...

Contrasting the Javascript onload event with plain script within an html page

Can you identify the distinction between these two code snippets: Sample 1: <script type="text/javascript> function myfunc () { alert('hi'); } window.onload = myfunc; </script> Sample 2: & ...

Troubleshooting a JavaScript Error in AngularJS Module

I created a Module called "app" with some helper functions in the file "scripts/apps.js": angular.module('app', ['ngResource']).run(function($scope){ $scope.UTIL = { setup_pod_variables: function (pods){...} ... }); Now, I want to ...

Change the color of the navbar when scrolling using bootstrap and jquery

Using Bootstrap to design a navigation bar, I have two main goals: I want the navbar to change color when the page is scrolled down by 20%, and then revert back to its original color when scrolling back to the top. When the collapse featu ...

Ways to turn off hover highlighting

Is there a way to disable the highlighting effect of the <select> element in HTML? When you hover over items in the dropdown list, a blue color strip moves with your mouse. I need to find a way to get rid of this effect. Here is an example of the c ...

Initiating an AJAX request to communicate with a Node.js server

Recently, I started exploring NodeJS and decided to utilize the npm spotcrime package for retrieving crime data based on user input location through an ajax call triggered by a button click. The npm documentation provides the following code snippet for usi ...

Learn how to convert data to lowercase using Vue.js 2

I am attempting to convert some data to lowercase (always lowercase) I am creating a search input like : <template id="search"> <div> <input type="text" v-model="search"> <li v-show="'hello'.includes(sea ...

Unable to upload gathered email to Mailchimp mailing list through Nodejs and express API

Seeking guidance on integrating data collection with Mailchimp in a Nodejs backend project. I am currently working on an email signup list page where users input their first name, last name, and email. The HTML file contains fields named firstName, lastN ...

Adding the "input-invalid" class to the input doesn't take effect until I click outside of the input field

When the zipcode field is updated, an ajax call is made. If there are no zipcodes available, I want to mark it as invalid by adding the "input-invalid" class. However, the red border validation only appears when clicking outside of the input field. Is ther ...

Creating HighStock charts on the server-side using NodeJS

I'm currently utilizing HighStock to create charts within the browser. However, I now have a need to save some of these charts on the server. While I understand that HighCharts offers an export option to the server, I am interested in exploring other ...

Displaying the URL of a link on the screen using jQuery

I am looking for a solution to add a link address after the link itself in a table containing reference links for our staff. I have used CSS to achieve this in the past, but the address was not copyable by users. Instead, I am interested in using jQuery&ap ...

Angular's Readonly component fails to display line breaks

I am currently developing an Angular application using C#. One issue I have encountered is with read-only components that display saved data from the database. For instance, when inputting text into a Textarea component, such as: hello there hello ...

Whenever the selected option in an HTML dropdown menu is modified, a corresponding input field should be automatically adjusted

Within my Rails application, I am facing a challenge related to updating the value of a text_field when a user chooses a different option from a select tag. The select tag is populated from a model which contains a list of countries for users to choose fro ...

Running PHP scripts from JavaScript

Currently working on a PHP project that involves a dropdown select button in a webpage. The goal is to call a JavaScript function whenever the value of the dropdown changes, and then pass this selected value to retrieve additional details from a MySQL da ...

Setting up vue-resource root and authentication configuration

Currently, I am reviewing the documentation for vue-resource that outlines how to configure it: https://github.com/vuejs/vue-resource/blob/master/docs/config.md The documentation specifies setting headers with a common authorization value: Vue.http.hea ...

JS Month Interval Bug Causing Issues with Chart Date

This script retrieves and summarizes download data from MySQL by day, displaying it as a chart. However, there's an issue with the way dates are handled between PHP and JavaScript (Highcharts). While PHP outputs month values from 1 to 12, JavaScript c ...

Utilizing express.js alongside the native MongoDB driver: A comprehensive guide

I'm facing difficulties when attempting a simple mongoDB query from my express app: app.js var express = require('express'); var routes = require('./routes'); var user = require('./routes/user'); var http = re ...

"Creating visual art with processing in 2D using P5

Recently, I came across a webpage about rendering 2D objects in processing using JavaScript. Here is the link to the page: Upon trying out the example code provided on the page in a new P5 project, I noticed that the code structure looked like this: HTML ...

Advanced automatic type inference for object literals in TypeScript

When working with TypeScript, I often declare generic functions using the syntax: const fn: <T>(arg: T)=>Partial<T> While TypeScript can sometimes infer the type parameter of a function based on its parameters, I find myself wondering if t ...