Tips on updating Angular data model when a static HTML element changes

Currently, I am utilizing the editable-table jQuery plugin to enable editing in a table. This tool is simple to implement, lightweight, and highly efficient.

The markup structure for this task looks like this:

<tr ng-repeat="o in orders">
   <td ng-bind="o.name"></td>
   <td ng-bind="o.weight"></td>
   <td ng-bind="o.dimensions"></td>
</tr>

To make the table editable, all it takes is calling the following function:

$('#ordertable').editableTableWidget();

This implementation functions smoothly: the table displays perfectly and supports editing capabilities. In case there are modifications in the data model, the table refreshes automatically.

However, using ng-bind results in one-way binding, meaning that alterations made in the table do not reflect in the data model without manual updates. Unfortunately, employing ng-model is not feasible as it requires an input field.

Since I am still learning Angular, I am uncertain about the appropriate method to synchronize changes back to the data model. While resolving it through plain JavaScript is possible, my preference is to stick with Angular conventions.

What would be the correct approach to update the data model accordingly?

Answer №1

In my opinion, it's best to avoid mixing the Angular way of updating values with an editable plugin. Since Angular is unaware of the plugin, their integration may not work as intended.

Instead of using a plugin, you could try implementing it without one:

<tr ng-repeat="o in orders">
   <td><input type="text"  ng-model="o.name" /></td>
   <td><input type="text"  ng-model="o.weight" /></td>
   <td><input type="text"  ng-model="o.dimensions" /></td>
</tr>

Answer №2

When you make changes using jQuery, the model is not automatically updated in Angular because Angular is not aware of the changes made and the digest cycle is not triggered. You can manually trigger the digest cycle like this:

$scope.$digest();
// However, this may not always work

Therefore, if you are using jQuery, you will need to explicitly assign a value to the model in order to update it.

Answer №3

If you're looking for an alternative solution to this issue, consider using the 'contenteditable' attribute in table cells with ng-model instead of ng-bind, instead of relying on the jQuery editable-table plugin. You can create a directive for contenteditable to update the model, and there is an example provided on the AngularJS site itself at the end of this page.

I have adapted the directive code from that example and made the necessary changes to your HTML.

directive('contenteditable', ['$sce', function($sce) {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
      if (!ngModel) return;

      ngModel.$render = function() {
        element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
      };

      element.on('blur keyup change', function() {
        scope.$evalAsync(read);
      });
      read();

      function read() {
        var html = element.html();
      
        if ( attrs.stripBr && html == '<br>' ) {
          html = '';
        }
        ngModel.$setViewValue(html);
      }
    }
  };
}]);

<tr ng-repeat="o in orders">
   <td contenteditable ng-model="o.name"></td>
   <td contenteditable ng-model="o.weight"></td>
   <td contenteditable ng-model="o.dimensions"></td>
</tr>

Answer №4

It's not recommended to use jquery based plugins in an angular app as they may not integrate well. It's better to search for angular-specific plugins.

What I did was take the input element utilized by the plugin for user input (Editable cell) and compile it using Angular's $compile service.

I believe this approach should be effective.

HTML :

 <div ng-app='app' ng-controller='mainCtrl' my-input>
     <table id="ir" >
       <tr ng-repeat="o in orders">
         <td ng-repeat="(key, value) in o"  ng-bind="value" ng-click="setCurrentCell($parent.$index, key)"></td>
       </tr>
     </table>
 </div>

Controller :

controller('mainCtrl', function($scope){
   setTimeout(function(){
      $('#ir').editableTableWidget();
   });

   $scope.orders = [{name:1, weight : 10}, {name:2, weight : 20}];
   var editableOrder  = {};
   $scope.setCurrentCell = function(index, key){
        editableOrder.index = index;
       editableOrder.key = key;
   }
   $scope.myEdit = function(newVal){
    $scope.orders[editableOrder.index][editableOrder.key] = newVal;
   }
})

Directive

directive('myInput', ['$compile', function( $compile){
   return {
      restrict: 'A',
      link: function(scope, element, attrs) {
            setTimeout(function(){
              var input = element.find('input');
              input.attr('ng-model', 'val');
              input.attr('ng-change', 'myEdit(val)');
              $compile(input)(scope);
           })
       }
   }
}]);

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

Creating a nested array of objects using a recursive function

How can I utilize my getChildren() function to create a larger function that takes my two main arrays objs and objRefs, and generates a single array of objs showcasing their parent/child relationship? Below are the two primary data arrays: const objs = [ ...

How long does it take to delete and recreate a cloudfront distribution using AWS CDK?

I am currently undergoing the process of migrating from the AWS CDK CloudfrontWebDistribution construct to the Distribution Construct. According to the documentation, the CDK will delete and recreate the distribution. I am curious about the total duration ...

Navigating to a specific state within a custom directive: A comprehensive guide

I've been experimenting with writing custom directives and encountered a challenge. I'm working on creating an ANCHOR BUTTON directive where I can set values for ICON, TEXT, and STATE(UI-SREF). HTML template <v-anc-btn-get state="profile( ...

Effective methods for transferring parameters between two separate JavaScript files within an express.js application

Currently, I am working with Express.js and facing a challenge in passing parameters from one JavaScript file to another. How can this be accomplished? The two files involved are 1. process.js var WebPageTest = require('webpagetest'); var wpt ...

How can we effectively manage error responses and retry a failed call in NodeJS without getting tangled in callback hell?

I am in search of an effective approach to handle the given situation. I am curious if employing promises would be a helpful solution? Situation Overview: When a call retrieves a callback, and this callback receives an error object as a parameter. My obj ...

Need to `come back` multiple times

I am facing an issue where I want to return multiple lines, but only the first line is being returned. I attempted to create a function specifically for returning the line, but encountered errors because I couldn't figure out where to place it. Does ...

Creating a monorepo project in JavaScript that mimics the structure of Visual Studio projects

When working on a typical .NET Core project (with Visual Studio 2019), the structure typically looks like this: Example/ |-- Example.Common/ | |-- FileExample1.cs | |-- FileExample2.cs | `-- Example.Common.csproj |-- Example.WebAPI/ | |-- Control ...

Managing the flow by utilizing nested promises within a loop

I'm struggling with managing the execution flow of my method using promises: //GET CHECKED OUT FILES getCheckedOutFiles = function () { console.log('Get checked out files'); var d = $q.defer(); // Store final results and pass t ...

Attempting to transmit a dynamic array of promises from Angular to an Express server

Currently, I am attempting to send an array of promises to an express app in order to retrieve data from a mongo database. The behavior seems to be working fine on the front end. In this scenario, both objects are sent to the server and resolved using $q ...

Send functions from the back-end Node to the front-end Angular

Introduction I am currently working on a project that involves verifying email addresses within an API in order to grant users access to a restricted section. To accomplish this, I have developed backend node code with three functions built using Node and ...

Automatically Populate Text Field with the URL of the Current Page

I am hoping to automatically fill a hidden text field with the URL of the current page so that I can keep track of where form submissions are coming from. This simple solution will help me streamline my inquiry responses and save time. To clarify, upon lo ...

How can I utilize Luxon to calculate the total number of days that are equal to or greater than 30?

Looking at my current array structure const arr = [ { id: '1', name: 'thing1', createdAt: '2022-09-21T16:26:02Z', }, { id: '2', name: 'thing1', createdAt: '2022-11-21T16:20:20Z', } ...

Is it possible to utilize the default error handling page rather than a specific view for expressing

Currently, I'm going through a tutorial on MDN Express for building a "Local Library" application that utilizes Pug (Jade) as its templating engine. In this segment of the tutorial, it explains the process of creating a controller to manage a form POS ...

Trouble with minified scripts on a particular server

Apologies if this has already been addressed, but I've been searching for a solution for hours. I created a basic website that works perfectly on my own hosting. However, when I transfer it to new hosting (same company, same package, different server ...

Validating a single field for City, State, and ZIP in jQuery/JavaScript

I am trying to validate an input field that requires City, State (two letter abbreviation), and ZIP code (5 numeric digits) in the format 'City, State ZIP'. Could someone please help me with validating this specific format and characters? Appre ...

Keep JS Accordion open when links are clicked

Utilizing PHP, I am fetching items from a database and creating an HTML table to display each item. Adjacent to the HTML table, there is a side menu with an accordion function implemented in JavaScript. Within each accordion section, there are links for ...

Proper positioning of try/catch block in scenarios involving delayed async/await operations

For the past six months, I have been utilizing async/await and have truly enjoyed the convenience it provides. Typically, I adhere to the traditional usage like so: try { await doSomethingAsync() } catch (e) {} Lately, I've delved into experimenti ...

What strategies can be employed to mitigate the activation of the losing arm in a Promise.race?

My current task involves sending the same query to multiple identical endpoints (about five) across various Kubernetes clusters. The goal is to aggregate the results without any delays and report failures to the user while continuing with the process seaml ...

Using a React button to sort through an array

Hey there, I'm currently working on an app that filters a list based on user input. The idea is to click on buttons to exclude users with specific letters in their names. However, the code I have right now isn't functioning properly. Any assistan ...

What is the process for extracting the differences between two or three files and merging them together in Node.js?

Recently, I've been experimenting with webpack and successfully managed to output and transform es5 build to include nomodule in the tags directly from HtmlWebpackPlugin using hooks. Similarly, for the es6 build, I added type="module". Howe ...