arame3333
arame3333

Reputation: 10193

Knockout: Change event does not work

On my webpage I have the following 2 inputs, the first one is textbox populated by autocomplete, and the second one is an ordinary textbox;

       <td style="width: 380px">
                <input type="text"
                       data-bind="enable: enableContract, jqAuto: {
                            source: getOptions,
                            value: SelectedContract,
                            labelProp: 'Label',
                            inputProp: JobDescription
                            }"
                       style="width: 99%;" />
            </td>
            <td style="width: 160px">
                <input type="text"
                       data-bind="value: Description, enable: enableContract, event: {change: disableContractIfConditionsMet}"
                       style="width: 99%;" />
            </td>

Just to complete the picture, when the autocomplete textbox is populated, the following 2 fields are populated;

self.ContractId = ko.pureComputed(function () {
    if (self.SelectedContract() != null) {
        return self.SelectedContract().Id;
    }

    return 0;
});



self.JobName = ko.pureComputed(function () {
    if (self.SelectedContract() != null) {
        return self.SelectedContract().JobName;
    }

    return "";
});

the value of the autocomplete textbox itself is set as follows;

self.SelectedContract = ko.observable(self.JobDescription());

What is not working is the change event on the second textbox. The intention is that when you enter the text "Sick" for example, it disables and clears the previous textbox (and set the ContractId to zero and JobName to empty - not coded yet). But this event is not executed when I leave the Description textbox. How do I get this to work?

Upvotes: 1

Views: 366

Answers (2)

Roy J
Roy J

Reputation: 43881

It's hard to say why your code isn't working, but here's a snippet that uses the change event to do what you describe, at least as far as disabling. I don't understand the jqAuto binding, so I don't know how to clear the value.

self = {
  SelectedContract: ko.observable(),
  JobDescription: ko.observable(),
  enableContract: ko.observable(true),
  Description: ko.observable('descrip'),
  disableContractIfConditionsMet: () => {
    if (self.Description() === 'Sick') {
      self.enableContract(false)
    }
  }
};
self.ContractId = ko.pureComputed(function() {
  if (self.SelectedContract() != null) {
    return self.SelectedContract().Id;
  }

  return 0;
});
self.JobName = ko.pureComputed(function() {
  if (self.SelectedContract() != null) {
    return self.SelectedContract().JobName;
  }

  return "";
});

ko.applyBindings(self);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>
  <input type="text" data-bind="enable: enableContract, jqAuto: {
                            source: getOptions,
                            value: SelectedContract,
                            labelProp: 'Label',
                            inputProp: JobDescription
                            }" style="width: 99%;" />
</div>
<div>
  <input type="text" data-bind="value: Description, enable: enableContract, event: {change: disableContractIfConditionsMet}" style="width: 99%;" />
</div>

Upvotes: 1

user3297291
user3297291

Reputation: 23372

I'd suggest not using the change event, but subscribing to the value bound observable instead.

var disableContractIfConditionsMet = function(currentDescription) {
  // Perform condition logic and set enable/disable states here
};

this.Description = ko.observable();
this.Description.subscribe(disableContractIfConditionsMet);

You can probably even create an enabled/disabled computed method that automatically updates based on the value of Description. I don't really understand the exact UI requirements though, so it's hard for me to write those...


An example of how you'd use a computed:

ko.applyBindings(new function() {
  
  var REQUIRED_VALUE = "test";
  
  this.secondInputValue = ko.observable("");
  this.firstInputEnabled = ko.computed(function() {
    return this.secondInputValue()
      .toLowerCase()
      .includes(REQUIRED_VALUE);
  }, this);
  
});
input {
  display: block;
  margin-bottom: 1rem;
}

input:disabled {
  background: rgba(0,0,0,0.2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<input data-bind="enable: firstInputEnabled">
<label>
  This input enables the first one if you type something containing "test"
<input data-bind="textInput: secondInputValue">
</label>

Upvotes: 3

Related Questions