Ashonko
Ashonko

Reputation: 613

knockout js remove function not working for nested table

I have been trying to remove the formulation elements with the 'Delete comp' link, but I'm not sure why it's not working. Also, the 'Add another composition' link is working once, but not multiple times. I'm working with Knockout.js and any explanation why this is not working will be greatly helpful.

    $( document ).ready(function() {
var initialData = [
    
];
 
var brandNamesModel = function(brandNames) {
    var self = this;
    self.brandNames = ko.observableArray(ko.utils.arrayMap(brandNames, function(drug) {
        return { brandName: drug.brandName, formulations: ko.observableArray(drug.formulations), compositions: ko.observableArray(drug.compositions) };
    }));
 
    self.addBrandName = function() {
        self.brandNames.push({
            brandName: "",
            formulations: ko.observableArray(),
            compositions: ko.observableArray()
        });
    };
 
    self.removeBrandName = function(drug) {
        self.brandNames.remove(drug);
    };
 
    self.addFormulations = function(drug) {
        drug.formulations.push({
            compositions: ko.observableArray()
        });
    };
 
    self.removeFormulations = function(formulation) {
        $.each(self.brandNames(), function() { this.formulations.remove(formulation) })
    };
    
    self.addComposition = function(drug) {
        drug.compositions.push({
            type: "",
            number: ""
        });
    };
 
    self.removeComposition = function(composition) {
        $.each(self.brandNames(), function() { this.compositions.remove(composition) })
    };
 
    self.save = function() {
        self.lastSavedJson(JSON.stringify(ko.toJS(self.brandNames), null, 2));
    };
 
    self.lastSavedJson = ko.observable("")
};
 
ko.applyBindings(new brandNamesModel(initialData));        
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class='container'>
   <h2>brandNames</h2>
   <div>
      <table>
         <tr>
            <th>Brand name</th>
            <th>formulations</th>
         </tr>
         <tbody data-bind="foreach: brandNames">
            <tr>
               <td>
                  <input data-bind='value: brandName' />
                  <div><a href='#' data-bind='click: $root.removeBrandName'>Delete brand name</a></div>
               </td>
               <td>
                  <table>
                     <tbody data-bind="foreach: formulations">
                         <tr>
                             <td><label>Formulation</label></td>
                             <td><select>
                                     <option>Tablet</option>
                                     <option>Syrap</option>
                                 </select>
                             </td>
                             <td><a href='#' data-bind='click: $root.removeFormulations'>Delete</a></td>
                                    
                             
                             <td>
                               <table>
                                   <tbody data-bind="foreach: compositions">
                                       <tr>
                                       <td><input data-bind='value: type' /></td>
                                       <td><input data-bind='value: number' /></td>
                                       <td><a href='#' data-bind='click: $root.compositions.removeComposition'>Delete comp</a></td>
                                    </tr>
                                   </tbody>
                               </table>
                              <a href='#' data-bind='click: $root.addComposition'>Add another composition</a>
                           </td>
                         </tr>

                     </tbody>
                  </table>
                  <a href='#' data-bind='click: $root.addFormulations'>Add formulations</a>
               </td>
               
            </tr>
         </tbody>
      </table>
   </div>
   <p>
      <button data-bind='click: addBrandName'>Add a drug</button>
      <button data-bind='click: save, enable: brandNames().length > 0'>Save to JSON</button>
   </p>
   <textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>
</div>

Upvotes: 1

Views: 144

Answers (1)

Nisarg Shah
Nisarg Shah

Reputation: 14531

It is clear that you need to formulation object to remove the composition. So in order to get the formulation along with composition, here's how I would write the click binding:

<a href='#' data-bind='click: function() {$root.removeComposition($data, $parent) }'>Delete comp</a>

Then, you could write the delete composition function as follows:

self.removeComposition = function(composition,formulation ) {
  formulation.compositions.remove(composition);
};

$( document ).ready(function() {
var initialData = [
    
];
 
var brandNamesModel = function(brandNames) {
    var self = this;
    self.brandNames = ko.observableArray(ko.utils.arrayMap(brandNames, function(drug) {
        return { brandName: drug.brandName, formulations: ko.observableArray(drug.formulations), compositions: ko.observableArray(drug.compositions) };
    }));
 
    self.addBrandName = function() {
        self.brandNames.push({
            brandName: "",
            formulations: ko.observableArray(),
            compositions: ko.observableArray()
        });
    };
 
    self.removeBrandName = function(drug) {
        self.brandNames.remove(drug);
    };
 
    self.addFormulations = function(drug) {
        drug.formulations.push({
            compositions: ko.observableArray()
        });
    };
 
    self.removeFormulations = function(formulation) {
        $.each(self.brandNames(), function() { this.formulations.remove(formulation) })
    };
    
    self.addComposition = function(drug) {
        drug.compositions.push({
            type: "",
            number: ""
        });
    };
 
    self.removeComposition = function(composition,formulation ) {
      formulation.compositions.remove(composition);
    };
 
    self.save = function() {
        self.lastSavedJson(JSON.stringify(ko.toJS(self.brandNames), null, 2));
    };
 
    self.lastSavedJson = ko.observable("")
};
 
ko.applyBindings(new brandNamesModel(initialData));        
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class='container'>
  <h2>brandNames</h2>
  <div>
    <table>
      <tr>
        <th>Brand name</th>
        <th>formulations</th>
      </tr>
      <tbody data-bind="foreach: brandNames">
        <tr>
          <td>
            <input data-bind='value: brandName' />
            <div><a href='#' data-bind='click: $root.removeBrandName'>Delete brand name</a></div>
          </td>
          <td>
            <table>
              <tbody data-bind="foreach: formulations">
                <tr>
                  <td><label>Formulation</label></td>
                  <td><select>
                                     <option>Tablet</option>
                                     <option>Syrap</option>
                                 </select>
                  </td>
                  <td><a href='#' data-bind='click: $root.removeFormulations'>Delete</a></td>


                  <td>
                    <table>
                      <tbody data-bind="foreach: compositions">
                        <tr>
                          <td><input data-bind='value: type' /></td>
                          <td><input data-bind='value: number' /></td>
                          <td><a href='#' data-bind='click: function() {$root.removeComposition($data, $parent) }'>Delete comp</a></td>
                        </tr>
                      </tbody>
                    </table>
                    <a href='#' data-bind='click: $root.addComposition'>Add another composition</a>
                  </td>
                </tr>

              </tbody>
            </table>
            <a href='#' data-bind='click: $root.addFormulations'>Add formulations</a>
          </td>

        </tr>
      </tbody>
    </table>
  </div>
  <p>
    <button data-bind='click: addBrandName'>Add a drug</button>
    <button data-bind='click: save, enable: brandNames().length > 0'>Save to JSON</button>
  </p>
  <textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>
</div>

Upvotes: 1

Related Questions