blog

Home / DeveloperSection / Blogs / How would you implement CRUD operations (Create, Read, Update, Delete) using Knockout.js?

How would you implement CRUD operations (Create, Read, Update, Delete) using Knockout.js?

How would you implement CRUD operations (Create, Read, Update, Delete) using Knockout.js?

Ravi Vishwakarma 170 27-Jun-2024

Implementing CRUD operations (Create, Read, Update, Delete) using Knockout.js involves integrating observable data bindings.

Example Implementation

HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Knockout.js CRUD Demo</title>
    <!-- Link to Bootstrap CSS for styling -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <!-- Link to jQuery library -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>

<body>
    <div class="container">
        <div class="d-flex justify-content-between mt-3">
            <h1>Product Management</h1>
            <div>
                <!-- Button trigger modal -->
                <button type="button" class="btn btn-primary" data-bind="click: showProductForm">
                    New Product
                </button>
            </div>
        </div>
        <hr />

        <!-- Product Display area -->
        <section class="">
            <!-- Show message to suer -->
            <div class="text-center" data-bind="if: products().length === 0">
                <p class=" fs-5 fw-bold ">
                    Your product display here.
                </p>
            </div>
        </section>

        <!-- Table to display products -->
        <div class="table-responsive" data-bind="if: products().length > 0">
            <table class="table">
                <thead>
                    <tr>
                        <th scope="col">#</th>
                        <th>Product Name</th>
                        <th>Product Price</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody data-bind="foreach: products">
                    <tr>
                        <th scope="col" data-bind="text: ($index() + 1)"></th>
                        <td><span data-bind="text: name"></span></td>
                        <td><span data-bind="text: price"></span></td>
                        <td class="d-flex">
                            <button class="btn btn-link text-primary"
                                data-bind="click: $parent.editProduct">Edit</button>
                            <button class="btn btn-link text-danger"
                                data-bind="click: $parent.deleteProduct">Delete</button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</body>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h1 class="modal-title fs-5" id="exampleModalLabel">New Product</h1>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <!-- Form to add new products -->
                <form class="row g-3" data-bind="submit: (isEditing() ? saveProduct : addProduct)">
                    <div class="col-12">
                        <label for="productName" class="fw-bold form-label">Product Name:</label>
                        <input type="text" class="form-control" placeholder="Product Name" id="productName"
                            data-bind="value: newProductName, valueUpdate: 'input'">
                    </div>
                    <div class="col-12">
                        <label for="productPrice" class="form-label fw-bold">Product Price:</label>
                        <input type="number" class="form-control" placeholder="Price" id="productPrice"
                            data-bind="value: newProductPrice, valueUpdate: 'input'">
                    </div>
                    <div class="col-12">
                        <button id="save-it" type="submit" class="btn btn-outline-primary px-4 rounded-pill">Add
                            Product</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>

<!-- Link to Knockout.js library for MVVM pattern support -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"
    integrity="sha512-vs7+jbztHoMto5Yd/yinM4/y2DOkPLt0fATcN+j+G4ANY2z4faIzZIOMkpBmWdcxt+596FemCh9M18NUJTZwvw=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.4/knockout.validation.min.js"
    integrity="sha512-b99MDNv5TqiZtPKH2UeHzDAVydmgrOJEPtaPPEF8AgV86eYyqINFI/K7/7f0+R4WNTAVv8KvvpjwfOYHv5rd5g=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
    crossorigin="anonymous"></script>
</html>

JavaScript 

Write ViewModel code with form validation code,

<script type="text/javascript">
    var modal = $('#exampleModal');

    function UpdateModal(isEditing) {
        modal.find('#exampleModalLabel').html(isEditing ? "Update Product" : "New Product");
        modal.find('#save-it').html(isEditing ? "Save" : "Save");
        modal.modal('show');
    }

    // Initialize Knockout validation
    ko.validation.init({
        registerExtenders: true, // Register custom validation rules
        messagesOnModified: true, // Show validation messages as soon as a field is modified
        insertMessages: true, // Insert validation messages next to the input elements
        parseInputAttributes: true, // Parse HTML5 input attributes for validation rules
        errorClass: 'text-danger fw-semibold', // CSS class for validation error messages
        messageTemplate: null // Use default message template
    }, true);


    function Product(id, name, price) {
        var self = this;
        self.id = ko.observable(id);
        self.name = ko.observable(name);
        self.price = ko.observable(price);
    }

    function AppViewModel() {
        var self = this;

        // Observables for new product input fields
        self.newProductName = ko.observable('').extend({
            required: {
                message: "Product name is required."
            },
            minLength: {
                message: "Product name must be at least 2 characters long.",
                params: 2
            }
        });
        self.newProductPrice = ko.observable('').extend({
            required: {
                message: "Price is required."
            },
            min: {
                message: "Price must be at least 1.",
                params: 1
            }
        });
        self.errors = ko.validation.group(self);

        // Observable array to store the list of products
        self.products = ko.observableArray([]);

        // Observables for editing a product
        self.isEditing = ko.observable(false);
        self.currentProduct = ko.observable(null);

        // Function to add a new product to the list
        self.addProduct = function () {
            if (self.errors().length === 0) {
                self.products.push({
 name: ko.observable(self.newProductName()), price: ko.observable(parseInt(self.newProductPrice())) }); self.newProductName(''); self.newProductPrice(''); // Hide modal using jQuery modal.modal('hide'); self.errors.showAllMessages(false); } else { self.errors.showAllMessages(); } }; // Function to start editing a product self.editProduct = function (product) { self.currentProduct(product); self.newProductName(product.name()); self.newProductPrice(product.price()); self.isEditing(true); UpdateModal(self.isEditing()); }; // Function to save changes to the edited product self.saveProduct = function () { if (self.errors().length === 0) { var product = self.currentProduct(); product.name(self.newProductName()); product.price(parseInt(self.newProductPrice())); self.isEditing(false); modal.modal('hide'); self.errors.showAllMessages(false); } else { self.errors.showAllMessages(); } }; // Function to delete a product from the list self.deleteProduct = function (product) { if (window.confirm("Are you sure, You want to delete this product.")) { self.products.remove(product); } }; self.showProductForm = function () { self.newProductName(''); self.newProductPrice(''); self.isEditing(false); UpdateModal(self.isEditing()); }; } // Apply Knockout.js bindings to the AppViewModel ko.applyBindings(new AppViewModel()); </script>

Explanation

HTML Structure:

  • Two sections: one for displaying products list (foreach binding), another for adding/editing products (submit, click bindings).
  • Each product in the list has buttons for editing and deleting.

JavaScript :

  • Product Model (Product): Defines a Product class with observable properties (id, name, price).
  • ProductViewModel: Defines a view model with observable arrays (products), observable properties (productName, productPrice, currentProduct), and functions for CRUD operations (saveProduct, addProduct, deleteProduct, editProduct, showProductForm).
  • saveProduct: Handles update (PUT)  operations for products.
  • addProduct: Handles create (POST) operation for product
  • deleteProduct: Sends a DELETE request to remove a product from the source.
  • editProduct: Sets selected product for editing and populates form fields.

 

Read more 

Getting Started with Templates in Knockout.js

Knockout.js: Building Dynamic Web Applications

Integrating Knockout.js with RESTful APIs

Product Drag and Drop with Knockout


Hi, my self Ravi Vishwakarma. I have completed my studies at SPICBB Varanasi. now I completed MCA with 76% form Veer Bahadur Singh Purvanchal University Jaunpur. SWE @ MindStick | Software Engineer | Web Developer | .Net Developer | Web Developer | Backend Engineer | .NET Core Developer

Leave Comment

Comments

Liked By