Search code examples
javascriptjqueryknockout.jsoracle-jet

How to make linked(dynamic?) select fields in oracle jet?


Im very new to JS and OJET. I'm using oracle jet to create a form. I need to create two select fields, the firts displays a client's name and the next one must change is values with the selected client's team members.

I have a JSON File with this format:

{
"clients": [
    {
        "id": "C01",
        "name": "Client 1",
        "manager": "Manager 1",
        "team": [
            {
               "id": "C1MEM1",
               "name": "member 1"
            },
            {
                "id": "C1MEM2",
                "name": "member 2"
            },
            {
                "id": "C1MEM3",
                "name": "member 3"
            },
            {
                "id": "C1MEM4",
                "name": "Member 4"
            }
        ]
    },
    {
        "id": "C02",
        "name": "Client 2",
        "manager": "Manager 2",
        "team": [
            {
               "id": "C2MEM1",
               "name": "member 1"
            },
            {
                "id": "C2MEM2",
                "name": "member 2"
            },
            {
                "id": "C2MEM3",
                "name": "member 3"
            },
            {
                "id": "C2MEM4",
                "name": "member 4"
            }
        ]
    }

I managed to create a select field with the clients name:

self.clientsListVal = ko.observableArray(['C01']);
  self.clientsList = ko.observableArray();
  $.getJSON("http://localhost:8000/js/json/clients.json").
    then(function(data){
      $.each(data["clients"],function(){
        self.clientsList.push({
          value: this.id,
          label: this.name
        });
      });
    });

Then I tried to get the next select fields this way, but it doesn't work :( :

self.memberList = ko.observableArray();

$.getJSON("http://localhost:8000/js/json/clients.json").
then(function(data){
    $.each(data["clients"],function(){
        if (this.id === self.clientsListVal ) {
            $.each(this["team"], function(){
                self.memberList.push({
                    value: this.id,
                    label: this.name
                });
            });
        }
    });
});

This is the HTML im using:

    <div class="oj-applayout-content">
<div role="main" class="oj-hybrid-applayout-content">
  <div class="oj-hybrid-padding">
    <h3>Dashboard Content Area</h3>
    <div>
        <label for="clients">Clients</label>
        <select id="clients"
        data-bind="ojComponent:
        {component: 'ojSelect',
        options: clientsList,
        value: clientsListVal,
        rootAttributes: {style:'max-width:20em'}}">
        </select>


        <label for="select-value">Current selected value is</label>
        <span id="select-value" data-bind="text: clientsListVal"></span>

        <label for="members">Members</label>
        <select id="members"
        data-bind="ojComponent: {component: 'ojSelect',
        options: memberList,
        value: memberListVal,
        rootAttributes: {style:'max-width:20em'}}">
        </select>
    </div>
  </div>
</div>

Any help or hint? thank you!.

EDIT: I think the problem is that self.clientsListVal is returning a function not the current selected value. I added console.log(self.clientsListVal) to the view model to see the current value.

If I change self.clientsListVal for a string:

if(this.id === 'C01'){}

I get the members of the client "C01".

I tried changing self.clientsListVal to $('#clients').val(), this is the id of the select input and i get undefined in the console.log.

How can I get the select field string value inside the viewmodel?


Solution

  • In Knockout, observables are functions -- so when you ask for the observable directly, like self.clientsListVal, you get the function definition. To get the underlying value, call the observable like a function: self.clientsListVal().

    So your test becomes if (this.id === self.clientsListVal() ) {

    Now you have another problem -- the observable holds an array, not an ID. The array may have a single ID element in it, but you have to reach into the array to get it.

    Since you didn't show us how a value gets into clientsListVal, it's hard to say what you need to do. Is it bound to an input field where the user specifies a value? Is it populated from a data call? either way, do you ever need to have more than one ID in clientsListVal? If you only need to hold one ID at a time, change clientsListVal from an observableArray to a simple observable and your test will work.

    If clientsListVal can hold multiple values, you'll need to loop over them. There are various ways to do this. You can get the underlying array by assigning the value of the observableArray to a variable: var clients = clientsListVal(). clients now holds the array, and you can use jQuery's $.each, the native Array.each, or some other way to loop over or map the array. Or you can use Knockout's built-in array utilities, like arrayForEach

    if you don't want to change to a regular observable but expect the array to only have a single element, you can get at it like clientsListVal()[0] -- that's the 0th (first) element of the array. Watch out for empty arrays, tho.