Modify the database entry only if the user manually changes it, or temporarily pause specific subscriptions if the value is altered programmatically

After a change in the viewmodel, I want to immediately update the value on the server.

class OrderLine
{
    itemCode: KnockoutObservable<string>;
    itemName: KnockoutObservable<string>;

    constructor(code: string, name: string)
    {
        this.itemCode = ko.observable(code);
        this.itemName = ko.observable(code);
        
        this.itemCode.subscribe(this.updateCode, this, "change");
        this.itemName.subscribe(this.updateName, this, "change");
    }

    updateCode = (newvalue: string) =>
    {
        //Update value on the server
    }

    updateName = (newvalue: string) =>
    {
        //Update value on the server
    }
}

Users can change both values, and with explicit subscriptions, updating to the server/database works correctly.

On the server side, updating itemCode will also update the value of itemName. Thus, the response to the client will include a json object with the new value for itemName

The issue arises when changing the value of itemName in the viewmodel triggers a subscription callback method that updates the same value on the server again

    updateCode = (newvalue: string) =>
    {
        //Update value on the server
        //Upon successful request
        this.itemName(updatedvaluefromServer);   
    }

Question: Is it possible to change the value of a KnockoutObservable that only notifies view subscribers?
Or is there a way to detect if the value was changed from the view?

I attempted to use the "sneaky update" technique by @RPNiemeyer mentioned here
However, this approach suspends notification for all subscribers, including those in the view

Answer №1

Check out this innovative approach that combines a computed observable with a regular observable:

class ProductItem
{
    private _itemNumber: KnockoutObservable<string>;
    private _itemName: KnockoutObservable<string>;
    itemNumber: KnockoutComputed<string>;
    itemName: KnockoutComputed<string>;

    constructor(number: string, name: string)
    {
        this._itemNumber = ko.observable(number);
        this._itemName = ko.observable(name);

        this.itemNumber = ko.computed({
            read: () => this._itemNumber(),
            write: (newVal) => {
                this._itemNumber(newVal);
                // Update database
                // Upon a successful response:
                this._itemName("...");
            }
        });

        this.itemName = ko.computed({
            read: () => this._itemName(),
            write: (newVal) => {
                this._itemName(newVal);
                // Update database
            }
        });
    }
}

Remember to update the underlying observable in the success callback of your AJAX requests, rather than directly in the write function of the computed property, to avoid any issues.

Answer №2

Let me explain the concept I mentioned earlier. The code is an observable value, while the name is a writable computed value. When the code gets updated, it automatically updates the read value of name. On the other hand, when you write to the name, it updates the code which in turn updates the read value of name. This results in only one update to the observable value of name, so there are not two separate updates.

If you observe the console carefully, you will see that updating either field triggers a single update for each of them.

function orderLine(code, name) {
  return {
    code: code,
    name: name
  };
}
var serverValues = [
  orderLine(1, 'one'),
  orderLine(2, 'two'),
  orderLine(3, 'three')
];

function getNameFromCode(code) {
  var found = ko.utils.arrayFilter(serverValues, function(line) {
    return line.code == code;
  });
  if (found.length == 0) return '';
  return found[0].name;
}

function getCodeFromName(name) {
  var found = ko.utils.arrayFilter(serverValues, function(line) {
    return line.name == name;
  });
  if (found.length == 0) return '';
  return found[0].code;
}

function vm() {
  var self = {};
  self.code = ko.observable();
  self.name = ko.computed({
    read: function() {
      return getNameFromCode(self.code());
    },
    write: function(newValue) {
      console.debug("Writing code");
      self.code(getCodeFromName(newValue));
    }
  });

  self.code.subscribe(function(newValue) {
    console.debug("Updating code to:", newValue);
  });
  self.name.subscribe(function(newValue) {
    console.debug("Updating name to:", newValue);
  });

  return self;
}

ko.applyBindings(vm());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<label>Code</label>
<input data-bind="value:code" />
<br />
<label>Name</label>
<input data-bind="value:name" />

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 there a beginner's pack or trial version available for utilizing TypeScript with IBM Cloud Functions / OpenWhisk?

While working on developing actions in IBM Cloud Functions, I have been primarily using Node.js / Javascript and Python for coding. However, I haven't come across specific instructions on how to incorporate TypeScript into IBM Cloud Functions. I am c ...

Exploring the Power of React's Ref API

Currently, I am following tutorials on Udemy by Max where he discusses how to work with Ref Api's in React 16.3. In one of the lectures, he demonstrated creating a ref inside a container class, not App.js, using this.lastref = React.createRef();. He ...

Looking to establish combinations in typescript? The answer lies in utilizing a discriminated union

I've been working with Typescript and I'm curious if it's possible to specify the valid combinations of input for a function. Below is a simplified version of the code: interface ActionType { type: string, payload: { count?: ...

The typings for object properties in Typescript

I recently encountered a function call in my code: var myVar = myFunction({ property: 'prop', functionProperty() { console.log(this.property); }, functionProperty2() { this.functionProperty(); } }); I' ...

Unable to detect tsc after installing globally within Windows Sandbox

I followed the instructions provided here to install TypeScript globally. npm install -g typescript After installing both inside vscode and outside, I encountered an issue where tsc --version does not work and shows 'tsc is not recognized'. Int ...

What is the proper method for utilizing the "oneOf" keyword in this schema?

Is it possible to have either option A or B, but not both (mutually exclusive)? In Draft 3, I am required to use whatever is available, even though the version on top says 4. This is because when using an array for "required", it throws an error stating t ...

I need help on correctly retrieving the ng-model value in a controller when using it with the contenteditable directive

I've attempted using ng-change, ng-keypress, ng-keyup, and ng-keydown for this issue. Using ng-change, the ng-model value is being updated in the controller but not reflecting on the front end. However, with the other three methods, the value displa ...

TypeScript in Angular causing lodash tree shaking failure

I am currently working on a large project that involves TypeScript. Various attempts have been made to optimize the use of lodash in my project. Before making any conclusions, I believe it is important to review the outcomes of my efforts. The command I ...

Exploring the world of reactive programming in JavaScript by transforming traditional AJAX calls into Bacon.js streams while incorporating

How can I develop a method to convert calls to the server API to a Bacon.js / RxJs stream while supporting pagination? With pagination, I aim to keep track of the last requested item index and retrieve the next set of items based on the page size to popul ...

modify the color of text in a row within a jquery ajax table

Is it possible to change the font color of values in a row based on a condition inside a function? Specifically, if the TotalStudent count exceeds the room capacity, can we add student information to the table with red font color? Below is my attempt using ...

Is there a way to search for multiple items using just one search term?

On my app, there is a search bar that currently only looks up data for one specific attribute. For example, if I type in "Hammer," it only searches for Tool names. Now, I need to expand the search functionality to accommodate different types of strings. F ...

Refresh the current page with jQuery Mobile when it is clicked

I have a multi page template in jQuery Mobile. How can I refresh the current page when clicking on a hyperlink or button? I am using JQM version 1.4.5 Despite trying the code suggested in how to refresh(reload) page when click button in jQuery Mobile, it ...

When using Typescript inheritance, the datatypes shown in IntelliSense are unexpectedly listed as "any" instead of

In my Typescript code, I have a small implementation where a class is either implementing an interface or extending another class. interface ITest { run(id: number): void } abstract class Test implements ITest { abstract run(id); } class TestEx ...

An error was encountered while attempting to utilize Google's Core Reporting API: Uncaught SyntaxError: Unexpected token <

I've been experimenting with Google's Core Reporting API and successfully implemented their provided demo. Now, I'm trying to integrate the code into my own project. My main tech stack includes AngularJS and PHP. I aim to keep it simple by ...

What steps can be taken to avoid an abundance of JS event handlers in React?

Issue A problem arises when an application needs to determine the inner size of the window. The recommended React pattern involves registering an event listener using a one-time effect hook. Despite appearing to add the event listener only once, multiple ...

Struggling with setting up a PHP and Ajax registration and login system

Struggling with my code and in need of assistance. Desperately trying to set up a register form where users can input their username and password to sign up. Planning to utilize ajax, however, the integration seems faulty. For testing purposes, I tried ech ...

What is the method to invoke a function within a factory in angularjs by using a string parameter?

I have a complex logic that I want to encapsulate in an AngularJS factory for easy use with dependency injection. The challenge is that the logic is dynamic, so I don't know in advance what functions will be available. What I have is a string represen ...

Error: Unable to locate the reference

Having trouble with my JavaScript code not recognizing the linked .js files I added. I initially linked them through CodePen, but manual references don't seem to be working. Attempted suggestions from this page Why does jQuery or a DOM method such as ...

Duplicate text content from a mirrored textarea and save to clipboard

I came across some code snippets here that are perfect for a tool I'm currently developing. The codes help in copying the value of the previous textarea to the clipboard, but it doesn't work as expected when dealing with cloned textareas. Any sug ...

Display the React component following a redirect in a Next.js application that utilizes server-side rendering

Just starting out with next.js and encountering a problem that I can't seem to solve. I have some static links that are redirecting to search.tsx under the pages folder. Current behavior: When clicking on any of the links, it waits for the API respo ...