Enforce the splicing of the ng-repeat array with the utilization of track by

Our app incorporates a task list that can potentially grow to a substantial size. The main task list is accompanied by a sidebar, where selected tasks can be edited using a different controller (TasksSidebarCtrl instead of TasksCtrl which handles the list display). The selected task is duplicated and then merged back into the list, with communication managed through TasksService.

The significant number of watchers per task in the index prompted us to explore alternative solutions.

Implementing one-time binding has successfully reduced the number of watchers (currently only the submenu for editing/changing task statuses without selecting in the sidebar generates watchers). However, due to our use of track by task.id (which we deem necessary given the numerous filters and frequent DOM changes), employing splice does not effectively remove and replace the task with the updated version - defeating the purpose of track by.

Is there a method to enforce the update of this task item while still utilizing both track by and one-time binding?

tasks-index.html (filters omitted for clarity)

<md-list-item my-task-directive ng-repeat="task in TasksCtrl.tasks track by task.id">

TasksCtrl

TasksService.index().then(function(tasks) {
    vm.tasks = tasks.data ? tasks.data : [];   
});

$scope.$on('task-updated', function() {
    var newTask = TasksService.getUpdatedTask();
    $timeout(function() {
        vm.tasks.splice(newTask.index, 1, newTask.task);
    });
});

TaskSidebarCtrl

$scope.$watch(function() {
    return TasksService.getSelectedTask();
}, function (newVal, oldVal) {

    if (newVal !== oldVal) {
        /* Using copy here to prevent index view from updating during editing */
        vm.selectedTask = angular.copy(newVal);
        vm.index = TasksService.getSelectedTaskIndex();

    }
});

TasksService.update(vm.selectedTask).then(function(data) {
    // handle notifications etc., then...
    TasksService.updateTaskInIndex(vm.index, data.data);
});

TasksService

var selectedTask = {};
var indexOfTask;
var updatedTask = {};
var updatedIndex;

this.setSelectedTask = function(task, index) {
    selectedTask = task;
    indexOfTask = index;
};
this.getSelectedTask = function() {
    return selectedTask;
};
this.getSelectedTaskIndex = function() {
    return indexOfTask;
};
this.getUpdatedTask = function() {
        return {
            'index': updatedIndex,
            'task': updatedTask
        };
};
this.updateTaskInIndex = function(index, task) {
    updatedTask = task;
    updatedIndex = index;
    $rootScope.$broadcast('task-updated');
};

Using a basic angular.copy (with destination) instead of TasksService.updateTaskInIndex(vm.index, data.data) in TaskSidebarCtrl's update function results in the one-time bound properties not being updated in the index view due to the one-time binding constraint. While this approach functions without track by task.id, we are reluctant to make such compromises if feasible, and wish to maintain the use of one-time binding.

Is there a workaround?

Answer №1

When the track by task.id remains the same for an updated task, the DOM elements will not be rebuilt and existing expressions in that element will not update due to one-time binding.

To ensure that the old task's node is removed and a new one is inserted with updated expressions evaluated, use a track by expression that changes when the entry is updated. One way to achieve this is by assigning a tracking_id property to the task with a format of "{id}_{version}", where the version changes with each update. Then, utilize track by task.tracking_id.

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

Is it possible to assign multiple ID's to a variable in jQuery?

I am currently using a script for a slider known as Slicebox, and in order to have different image sizes for mobile and desktop views, I need to duplicate the feature on my website. Although it's not ideal, I really like this slider and want to explo ...

Is there a way to modify the appearance of blocks in Scratch/Blockly?

I am currently working on customizing the appearance of the blocks in Scratch by looking into adjusting the GitHub repository of scratch-blocks (https://github.com/LLK/scratch-blocks). There is a chance that I might need to modify the GitHub repository of ...

Changing a field in AngularJS to set validity as true in a different way

After following the guidance provided in this answer to implement custom server-side validation for a unique email constraint, I encountered an issue with my submit function on the controller: function submit(form){ CompanyUser.save(vm.model) .suc ...

Bizarre Actions of a JavaScript Object

Currently, I am in the process of developing a Multiplayer game using Phaser and Eureca io. My main focus right now is on perfecting the authentication of players and their controls. To achieve this, I have implemented a method on the server that retrieves ...

Combine two SCOPES obtained from different origins (but the same structure)

I have a function that updates every 30 seconds and pulls of a list of services. However, I would like to expand this to also pull from different endpoints in the URL: $http.get('(url of remote site)/pad/20?expand=true') and $http.get('( ...

Preventing the submission of a form using jQuery until all input, radio, select, and checkbox fields are filled out

I currently have a form that includes various field types, all of which must be filled out before submission. The submit button is disabled by default and I am looking to enable it once all fields are completed. I came across examples of this feature work ...

The use of `slot` attributes in Ionic has been deprecated and flagged by the eslint-plugin-vue

I encountered an error message while using VS Code: [vue/no-deprecated-slot-attribute] `slot` attributes are now considered deprecated. eslint-plugin-vue After installing two plugins in .eslintrc.js, I have the following configurations: 'extends&ap ...

Secure Access with Skype Bot Verification

Recently, I managed to set up a NodeJS bot to synchronize messages between Discord and Skype chats. Although I am relatively new to Javascript and completely unfamiliar with NodeJS, the existence of a framework called Spype has been quite beneficial. The i ...

Tricks for displaying a dynamic object tooltip in Three.js

Can anyone help me figure out how to create a HUD hint effect for a moving object? I envision something like this: An asteroid is floating through space, and when I click on it, a hint box with information pops up. I've been playing around with thi ...

Assistance with changing styles

Hey there, I could really use some assistance. I've created a style switcher, but I'm struggling to figure out how to replace the stylesheet properly. Currently, my code empties the <head> element when what I really need is for it to simply ...

In JavaScript, find a value in an array and substitute it with the value from the

One of my tasks involves manipulating a string variable in the following manner: domNodes += '<a href="javascript: void(0);" data-role="node_jump" data-node="'+this.tagName.toLowerCase()+'">'+this.tagName + "</a>" + " & ...

Switch between selection modes in React JS DataGrid using Material UI with the click of a button

I've been working on creating a datagrid that includes a switch button to toggle between simple and multiple selection modes. const dispatch = useDispatch(); const { selectedTransaction } = useSelector(...) const [enableMultipleSelection, setEnableMu ...

Inheriting Components from Templates

Insight on Motivation There are countless situations where we may require multiple components to share the same functionalities. It is not ideal (and definitely shouldn't be done!) to simply copy child components. This is where the concept of inherit ...

Using AngularJS to compile Sass

I have been struggling to get Sass working with the default compiler in Angular 2 despite trying various solutions. After importing the Bulma framework using Sass via npm install bulma, I attempted to include it in the styles.css file that comes with a fr ...

What methods are available to change one JSON format into another?

I am receiving JSON data from a Laravel API in the following format: [ { "id":48, "parentid":0, "title":"Item 1", "child_content":[ { "id":49, "parentid":48, "title":"Itema 1 ...

Customized Error Handling Function for Ajax Requests

I have a function that works perfectly, but I need to add six more buttons without repeating code. I want each callback to be customizable, with different text for each scenario (e.g. displaying "Please Log In" if the user is not an admin). How can I make ...

The color of the last clicked DIV is supposed to stay permanent, but for some unknown reason

I'm attempting to replicate this design in my project: http://jsfiddle.net/AYRh6/26/ However, I am facing issues with it and cannot pinpoint the exact problem in the code. I am using code for a toggle effect. Any assistance would be greatly appreciat ...

Tips for adding one document to two separate collections using JavaScript and MongoJS

Having trouble inserting data into two separate tables using javascript and mongojs. While I was able to successfully insert into a single collection by following the npm mongojs documentation, I couldn't find a solution for multiple collections on th ...

Sharing details of html elements using ng-click (AngularJS)

I am currently exploring options to enable users to click on a "open in new tab" link, which would essentially transfer that HTML element into a fresh window for their convenience. I am seeking advice on how to achieve this. At the moment, I am able to la ...

Converting text/plain form data to JSON using Node.js - step by step guide

I am currently working on a Node.js application to execute a POST call to an API for placing an order. However, the data I receive in our app is in text/plain format and not JSON. This is the current format of the data: TypeOrder=buy Coin=BTC AmountCoin= ...