0

Overview

This is a simple quotation app. I am currently developing the master quote page, where all quotes are shown.

The Problem

I am trying to display the client name in the master quote list. ( see pic ). The data the page relies on is in two tables:

enter image description here

  1. Quotes -- Holds the quote details
  2. Clients -- Holds client contact information

The tables are joined (related) by client_id

Knockout Implementation

I have defined a class to hold the quotes:

let QuoteModel = function(id, quote_number, created_date, expiration_date, amount, client, status){

     this.id = ko.observable();
     this.quote_number = ko.observable(quote_number);
     this.created_date = ko.observable(created_date);
     this.expiration_date = ko.observable(expiration_date);
     this.amount = ko.observable(amount);
     this.client = ko.observable(client);
     this.status = ko.observable(status);

}

and the Client Class

let ClientModel = function(id, fullName){
    this.id = ko.observable(id);
    this.fullName = ko.observable(fullName);
}

While looping through the quotes I imported via the API, I am grabbing the client_id and then calling a function to search the clients array and return the full name of the client.

I cannot figure out how to successfully search the clients array and return the full name.

Live URL

You can see the code fail here: http://quotes.123globalelectronicsllc.com/quotes.html

The View Model

Here is the view model:

// Quotes View Model

// +---------------------------------------------------------------------------+
// |  Quote View Model                                                         |
// |                                                                           |
// |  quotes-view-model.js                                                     |
// +---------------------------------------------------------------------------+
// |  Shows a list of all Quotes                                               |
// +---------------------------------------------------------------------------+/

let QuoteModel = function(id, quote_number, created_date, expiration_date, amount, client, status){

     this.id = ko.observable();
     this.quote_number = ko.observable(quote_number);
     this.created_date = ko.observable(created_date);
     this.expiration_date = ko.observable(expiration_date);
     this.amount = ko.observable(amount);
     this.client = ko.observable(client);
     this.status = ko.observable(status);

}



let ClientModel = function(id, fullName){
    this.id = ko.observable(id);
    this.fullName = ko.observable(fullName);
}


function QuoteViewModel() {

    var self = this; // Scope Trick


    /* QUOTE Observables */
    self.quotes = ko.observableArray();
    self.clients = ko.observableArray();

    /* GET PAGE DATA */

    /* CLIENTS */
           $.getJSON(apiCustomersAll,
            function(data) {
                var fullName;
                $.each(data,
                    function(key, val) {
                        fullName = val.first_name + " " + val.last_name;
                        self.clients.push(new ClientModel(val.id, fullName));
                    });
            });

          $.getJSON(apiQuotesAll,
            function(data) {
                var fullName;
                $.each(data,
                    function(key, val) {
                        fullName = self.getClientById(val.client_id);
                        console.log(`Full name is ${fullName}`);
                        self.quotes.push(new QuoteModel(val.id, 
                                                        val.quote_number, 
                                                        val.created_date, 
                                                        val.expiration_date, 
                                                        val.amount, 
                                                        fullName, 
                                                        val.status
                                                      ));
                    });
            });


        // Search Client Array, Return Full Name
        self.getClientById = function(id){

            $.each(self.clients(), function(key, val){
               alert(val.fullName);
                if(val.id() == id){
                    return val.fullName();   
                }
            });
        }


}


ko.applyBindings(new QuoteViewModel());

Can you see where I am going wrong? Any help would be greatly appreciated.

John S.
  • 504
  • 1
  • 3
  • 18

1 Answers1

1

The problem is in your getClientById method and specifically in the way you're trying to search - you use $.each to go over the elements:

$.each(self.clients(), function(key, val){
  alert(val.fullName);
  if(val.id() == id){
    return val.fullName();   
  }
});

However, you can't just return from $.each the way you're trying to. Here is a quote from the documentation:

We can break the $.each() loop at a particular iteration by making the callback function return false. Returning non-false is the same as a continue statement in a for loop; it will skip immediately to the next iteration.

Instead, you can use the Array#find method:

self.getClientById = function() {
  const client = self.clients().find(function(val){
    return val.id() == id
  }

  if(client) {
    return client.fullName();   
  }

  return undefined;
}

This can be even shorter using some ES6 syntax and short-circuiting

self.getClientById = function() {
  const client = self.clients().find(val => val.id() == id);

  return client && client.fullName()
}
VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • Thanks for this extremely informative answer. I have implemented your suggestions, and the solution works perfectly. The use of the short cut arrow method here is very interesting, something I definitely need to study up on. – John S. Jan 04 '20 at 08:55