Peurr Peurr - 5 months ago 60
Javascript Question

angularjs ng-model doesn't update

I have a Font Awesome icon picker, which I use for my application so the employees can easily access the different icons without searching for the codes online.

Now when I click on an icon, it does not update the ng-model. I first have to enter another character or a space for AngularJS to identify the changes made in the input.

https://i.gyazo.com/21d80e370726166a200f1165e169a0cf.gif, hereby the example of what's happening.

As you can see, in the bottom left I have made a label showing the data that's in the same ng-model. Now when I choose an icon, the model doesn't update. Only after I enter a space, or another character it's updating.

The code I have:

editCellTemplate: function (container, options) {
container.html('<input class="icon-picker-input edit icp icp-auto" type="text" ng-model="iconInput" /><script>$(".icp-auto").iconpicker();</script>');
options.setValue($scope.iconInput);
$compile(container)($scope);
}


I'm using a gridview from DevExtreme with a custom
editCellTemplate
.

The binding:

enter image description here

Which is declared here:

enter image description here

Does anyone have a clue on how to fix this? Thanks in advance!

Answer

The main reason your code isn't working as intended is that Angular only watches for user interaction events in order to update the model. Your icon picker completely bypasses Angular by directly setting the value in the input.

In order to update the model you need to set a hook on the icon picker updating process : whenever you select an icon, either overwrite the iconInput scope variable yourself (and wrap this in a $scope.$apply call) or much more simply, trigger the 'input' event on the input element, which will cause Angular to pick up the new value (see here).

I suggest you do something like this :

editCellTemplate: function (container, options) {
    container.html('<input class="icon-picker-input edit icp icp-auto" type="text" ng-model="iconInput" />');
    options.setValue($scope.iconInput);        
    $compile(container)($scope);

    // Avoid inline script tags, you can make the iconpicker here
    $(".icp-auto").iconpicker();

    // Watch for icon picker selections
    $(".icp-auto").on('iconpickerSelected', function(e) {
        // Fire the "input changed" event
        $(e.currentTarget).trigger('input');
    });
}

Notice I removed the script tag inside your compiled html because you can perfectly instantiate the icon picker in your main code. Script tags evaluate in the global context which is often not what you want.

Update : The compile-time error you reported in your comment is due to the fact that your Typescript setup has a definition for the JQuery class (probably a jquery.d.ts file) which does not include an iconPicker() method. At runtime the content of the <script> tag compiled in Angular is directly interpreted as plain Javascript, avoiding Typescript's type checking.

See this answer for a simple way to enable additional methods on the JQuery interface. I strongly recommend you stop putting logic in compiled <script> elements, there is a high chance it will come back to bite you.

Comments