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

angularjs directive inside ng-app not functioning

So I came across a code snippet like this: base.html {% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewp ...

Menu options

I am currently working on developing a mouseover navigation website. Initially, my design included main buttons for "Our Team", Locations, and Patient Resources. Here is the basic structure I had before attempting to switch to a mouseover approach... &l ...

Conceal the sidebar menu by clicking anywhere outside of the menu bar or the designated button

I attempted to create a menu similar to the semantic UI, but so far I have only been able to click the menu button to open and close the menu. I am using a toggle class to display the sidebar, but I'm unsure if this approach is entirely correct: < ...

Exploring Javascript through Python using Selenium WebDriver

I am currently attempting to extract the advertisements from Ask.com, which are displayed within an iframe generated by a JavaScript script hosted by Google. Upon manually navigating and inspecting the source code, I can identify the specific element I&ap ...

What is the best way to hide the jQuery modal I created?

Hello everyone! Currently, I am working on coding a simple JS modal that can be opened and closed smoothly. The issue I am facing is related to adding a click function to (.black-overlay) in order to fade out everything and close the modal. <div class ...

Tips for retrieving headers from a POST response using AngularJS $http

Before moving forward, it's important to note that this scenario occurs within a CORS environment. On Server #1 (http://localhost:33233), which is my main website hosting SOAP and WebAPI services, I have added the following lines to the Global.asax i ...

substitute a component with a different one if it is present

I'm currently working on a script that will automatically replace one element with another as soon as it is created, even when the page loads. Despite my attempts to use MutationObserver, I haven't been successful. var target = document.querySe ...

Error encountered during Jest snapshot testing: Attempting to destructure a non-iterable object which is invalid

I am currently facing an issue with my React codebase where I am attempting to create snapshot tests for a component. However, Jest is showing an error indicating that I am trying to destructure a non-iterable instance. Despite thoroughly reviewing the cod ...

Sending JSON data from the primary window to the secondary window in Electron - A step-by-step guide

I am currently working with a set of 3 files. index.html: ... <a href="#" onclick="fetch(function(data) {console.log(data); subWindow(data)})">subWindow</a> ... The fetch() function retrieves a callback in JSON format. subWindows.js: let m ...

Insert PHP File into Division Element

Need help loading a PHP file into a div element without removing existing content? Here's an example: $('.Load_Div').load('example.php'); Let's say the Load_Div already has some content that you want to keep, and you want th ...

Get user input from a textbox and use that input to conduct a search on Google

Hi there, I'm currently working on solving this particular problem. I'm attempting to create a HTML page using a form where the user can input a keyword and click on the "Search" button to search for that keyword on Google. I haven't had a ...

Update in slide height to make slider responsive

My project involves a list with text and images for each item: <div class="slider"> <ul> <li> <div class="txt"><p>First slogan</p></div> <div class="img"><img src="http://placehold.it/80 ...

Is the $http call for OPTIONS instead of POST?

Hey there, I'm encountering a strange issue while trying to call my backend using the POST method. Remote Address:192.168.58.183:80 Request URL:http://192.168.58.183/ESService/ESService.svc/CreateNewAccount Request Method:OPTIONS Status Code:405 Meth ...

Guide on displaying ajax data using PHP

I'm attempting to display the user-entered data by using AJAX to transfer it and then trying to print or echo it with PHP, but I'm having trouble getting it to work. enter code here Here is my code: <html> <head> <title> ...

The Date Picker pops up automatically upon opening the page but this feature is only available on IE10

There seems to be an issue with the date picker opening automatically on IE10, while it works fine in Firefox where it only appears when you click on the associated text box. Does anyone have insight into why this might be happening specifically in IE10? ...

Guide on verifying internet connection status using Ajax request

Ensuring authentication by checking the availability of network connection on mobile devices. To do this, we must have both a username and password. The authentication process will be conducted online, requiring an active internet connection on the device. ...

Does the entire window fade before the URL is loaded?

Is it feasible for me to create an effect where, upon a user clicking on a link, the entire window fades out (perhaps with a black div covering it), and then loads an external URL like 'google'? For example: User clicks 'Here', and th ...

Using $http to pass a parameter to an Angular factory

This is my AngularJS factory responsible for supplying autocomplete data: app.factory('autoCompleteDataService', ['$http', function($http) { return { getSource: function(callback, url) { var apiUrl = & ...

Manage the application of CSS media queries using JavaScript

Is there a method to control which CSS media query a browser follows using JavaScript? As an example, let's say we have the following CSS: p { color: red; } @media (max-width: 320px) { p { color: blue; } } @media (max-width: 480px) { p { col ...

Re-establishing the socket channel connection in a React application after a disconnection

There are several solutions to this issue, but none of them seem to be effective for me. The existing solutions are either outdated or do not meet my needs. I am facing a problem where I have a large amount of data being transferred from the server to the ...