Creating a single editable row using KnockoutJs in a data grid

I am currently working on implementing an editable datagrid feature. My goal is to click on the Edit button and only have the selected row become editable, instead of all rows becoming editable at once. I have created two templates: one for displaying data and one for editing:

<table class="table">
        <thead>
            <tr>
                <th>Id</th>
                <th>Number</th>
                <th>Capacity</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody id="room" data-bind="template: {name: selectedTemplate, foreach: roomList}"></tbody>
    </table>

    @*Templates*@
    <script type="text/html" id="baseTemplate">
        <tr>
            <td data-bind="text: id"></td>
            <td data-bind="text: number"></td>
            <td data-bind="text: capacity"></td>
            <td>
                <button type="button" data-bind="click: function() { $root.edit($data) }">Edit</button>
            </td>
        </tr>
    </script>

    <script type="text/html" id="editTemplate">
        <tr>
            <td data-bind="text: $root._id"></td>
            <td>
                <input type="text" class="form-control" data-bind="value: $root._number" />
            </td>
            <td>
                <input type="text" class="form-control" data-bind="value: $root._capacity" />
            </td>
            <td>
                <button type="button" data-bind="click: function() {$root.update($data)}">Update</button>
            </td>
        </tr>
    </script>
    

ViewModel written in TypeScript:

import * as ko from 'knockout';
import { RoomDTO } from "./../DTO/roomDTO";

class RoomIndexVM {
    roomList: KnockoutObservableArray<RoomDTO>;
    selectedTemplate: KnockoutObservable<string>;

    _id: KnockoutObservable<number>;
    _number: KnockoutObservable<number>;
    _capacity: KnockoutObservable<number>;

    constructor() {
        this.roomList = ko.observableArray();
        this.selectedTemplate = ko.observable("baseTemplate");

        this._id = ko.observable();
        this._number = ko.observable();
        this._capacity = ko.observable();
    }

    private getAllRooms() {
        return new Promise<Array<RoomDTO>>((resolve) => {
            $.ajax({
                type: "GET",
                url: `/api/room/getall?skip=${0}&take=${0}`
            }).done((result: Array<RoomDTO>) => {
                resolve(result);
            }).fail(function (ex) {
                console.log(`Error: ${ex}`);
            });
        });
    }

    private updateRoom(data: RoomDTO) {
        return new Promise<number>((resolve) => {
            $.ajax({
                type: "POST",
                contentType: "application/json",
                data: JSON.stringify(data),
                url: `/api/room/update`
            }).done((result: number) => {
                resolve(result);
            }).fail(function (ex) {
                console.log(`Error: ${ex}`);
            });
        });
    }

    private updateRoomList(result: Array<RoomDTO>) {
        this.roomList.removeAll();

        result.forEach((value, index) => {
            this.roomList.push(value);
        });
    }

    public changeTemplate(template: string) {
        switch (template) {
            case "base":
                this.selectedTemplate("baseTemplate");
                break;
            case "edit":
                this.selectedTemplate("editTemplate");
            default:
        }
    }

    public async edit(room: RoomDTO) {
        this.changeTemplate('edit');
    }

    public async update(room: RoomDTO) {
        alert("in edit");
        this.changeTemplate("base");
        console.log(await this.updateRoom(room));
        this.updateRoomList(await this.getAllRooms());
    }

    public async initialize() {
        this.updateRoomList(await this.getAllRooms());
    }
}

window.onload = () => {
    let roomIndexVM = new RoomIndexVM();
    ko.applyBindings(roomIndexVM);

    roomIndexVM.initialize();
}

Click here to view the result after switching templates.

Can anyone guide me on how to make only one row editable at a time?

Answer №1

When the template name is shared among all list items, any edits made to one will affect the template for all.

To solve this issue, it's best to create a unique observable property for each individual list item.

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

The ASP.net MVC - Razor HTML Helper seems to have a firm grip on memory, refusing to release it

My new ASP.Net MVC project is experiencing memory consumption issues that I can't seem to figure out. About the Project The project consists of just 2 pages, both controlled by the HomeController. public class HomeController: Controller ...

Ways to maximize the benefits of a stateless framework

Looking to implement the http://code.google.com/p/stateless framework in my code for separating functionality from dependencies. I'm seeking best practices for utilizing this stateless framework, as I couldn't find many advanced usage examples. ...

Difficulty encountered while trying to link an abstract class with Redux state using redux-thunk

My approach to using redux-thunk and class components in React follows a basic pattern. The code below shows how a class definition MyClass is exported, correctly connected to state through mapStateToProps, and has access to actions from mapDispatchToProps ...

A guide on leveraging the modal window function within Angular

I have a simple list of files with a "Delete" button. I have added a modal window for confirmation, but I am unsure how to connect the Delete function from the main component to the modal window. The modal window is implemented using the @angular/materia ...

Exploring TypeScript's Generic Types

Currently, I am engaged in a frontend project using Angular for my company. Our main task is to retrieve various objects from an API such as Users, Products, etc. I am focusing on streamlining our services responsible for transferring data between compone ...

Transform the object into an array of bytes

I need to convert a registry value, stored as REG_BINARY, from object to byte[]. I attempted to use BinaryFormatter with MemoryStream, but it added unnecessary overhead information. I noticed this when converting the byte array to a string using Convert. ...

What is the best way to convert an IEnumerable<DateOnly> into a serializable format?

I created a personalized JsonConverter to serialize the DateOnly data type, however I am unsure about how to utilize this converter with a collection such as IEnumerable. ...

What is the most effective method for testing a function that retrieves input values from an HTML input element?

I am facing an issue while trying to test my function that extracts the value of an input element and assigns it to a local variable. Unfortunately, I am consistently encountering a type error message: Cannot read property 'nativeElement' of u ...

Images loading at a sluggish pace while utilizing the download.aspx feature

Our team has been working on implementing a download.aspx file to manage our source files, particularly images, for specific clients. We are using the buffering method in download.aspx.cs, with the code provided below: using (var fs = new FileStream(_path ...

Encountering a NullReferenceException while attempting to utilize the Null-conditional Operator in conjunction with

Why am I encountering a System.NullReferenceException when running the following code snippet: var response = new Response() { Id = request?.Event.Id }; Shouldn't I simply receive a Null value for the Id property (where Id is a string)? ...

Struggling to make Cypress react unit testing run smoothly in a ReactBoilerplate repository

I have been struggling for the past 5 hours, trying to figure out how to make everything work. I even recreated a project's structure and dependencies and turned it into a public repository in hopes of receiving some assistance. It seems like there mi ...

Incorporating the 7-zip library into a C# application built on the .NET framework

Similar Query: How to incorporate 7-Zip archives with .NET? Is there a way to seamlessly integrate the 7-zip archiving library into a C#.NET application? I have a project that requires an extraction utility for stored zip files, and I believe using 7Z ...

Angular2 array sorting function is not functioning properly on mobile browsers

I'm currently working with a code snippet that looks like this: const words = ['apple', 'banana', 'zoom'] words.sort((first, second) => { const a = first; const b = second; return a == b ? 0 : a < b || a == ...

Control the resume upload file

After reading through the following posts: Pause/Resume Upload in C# resume uploads using HTTP? I found that none of the solutions provided were ideal for my specific problem. One answer mentioned in the posts suggests using a Guid to identify the f ...

Steps to record and upload a video directly to the server using getusermedia

For my application, I need the user to record a video and have it saved on the server disk instead of downloading it to the client browser. I am currently using getusermedia for this purpose, with the following code: (function(exports) { exports.URL = exp ...

Nested Angular formArrays within formArrays

Currently working on inline editing in my project, I am attempting to patch value data from the server. Within my formArray for the accountNumbers array, I am encountering an issue when trying to change the value of inputs. The error message reads: Error: ...

Exploring directive unit testing in Angular without the use of TestBed and Component

I successfully implemented Unit Testing for a directive and it is working fine. However, I am curious to know if there is a way to test it without using a component and TestBed. How can I make improvements in my current setup? Also, what is the concept beh ...

Visual Studio encountering an error with AngularJS TypeScript integration

Hey everyone! I recently installed the angularjs.typescript and jquery.typescript packages from NuGet. However, I'm encountering errors in Visual Studio, as shown in the attached image. I'm using VS 2013 U4 and have updated all extensions and p ...

Combining Arrays with Typescript or JavaScript

I'm facing difficulty in merging two arrays into one. I have created an interface to retrieve data from MongoDB. export interface IWeeklyAssessmentData { dayName: string; dayDate: string; fromDb: boolean; } Here is a sample of the data fetched ...

When using a Redux action type with an optional payload property, TypeScript may raise complaints within the reducer

In my react-ts project, I define the following redux action type: type DataItem = { id: string country: string population: number } type DataAction = { type: string, payload?: DataItem } I included an optional payload property because there are tim ...