13

I am using HandsOnTable to make editing database tables more interactive on my site.

HandsOnTable fulfils nearly all my requirements except that some columns in my database actually store foreign keys rather than local string values.

In the UI I would like these columns to appear as dropdown menus where the user selects a readable value mapped to the previously mentioned foreign key (I.e. something like an HTML name/value select).

Unfortunately HandsOnTable does not have such a cell type. The closest thing to it is autocomplete. This allows me to create a dropdown, but it only contains values; no corresponding keys. Here is how it is created:

"source": ["Jebediah", "Bob", "Bill", "Buzz"]

So what I am planning is to send two Json strings from the server:

One containing the parameters needed by HandsOnTable to render the table:

{
    "data": [
        { "ID": 1, "Description": "Crude", "Volume": 204, "Customer": "jebediah" },
        { "ID": 2, "Description": "Hidrogen", "Volume": 513, "Customer": "Bob" },
        { "ID": 3, "Description": "Coal", "Volume": '67', "Customer": "Bill" },
        { "ID": 4, "Description": "Wood", "Volume": '513',  "Customer": "Buzz" }
    ],
    "columns": [
        { "data": "ID", "type": "numeric" },
        { "data": "Description", "type": "text"},
        { "data: "Volume", "type": "numeric" },
        { "data": "color", "type": "autocomplete", "strict": "true",
            "source": ["Jebediah", "Bob", "Bill", "Buzz"]}
    ]
}

The second mapping keys to values

{
    "mappings": [
        {"key": 0, "value": "Jebediah"}, 
        {"key": 0, "value": "Bob"},
        {"key": 0, "value": "Bill"}, 
        {"key": 0, "value": "Buzz"}
    ]
}

So far so good. Now for the tricky part:

HandsOnTable has a function (getData()) that allows me to retrieve the tables data as a Json string ready to be sent back to the server:

var jdata = myHandsOnTable.getData();

Where jdata would look something like this:

"data": [
    { "ID": 1, "Description": "Crude", "Volume": 204, "Customer": "jebediah" },
    { "ID": 2, "Description": "Hidrogen", "Volume": 513, "Customer": "Bob" },
    { "ID": 3, "Description": "Coal", "Volume": '67', "Customer": "Bill" },
    { "ID": 4, "Description": "Wood", "Volume": '513',  "Customer": "Buzz" }
]

Now before posting, I would like to replace that values for the Customer node with their matching pair key within the mappings json string.

How can I best achieve this in JavaScript/JQuery?

Is there a function that works something as follows?:

jdata.replaceNode('node', mappings)

Thanks

Chopo87
  • 1,170
  • 4
  • 17
  • 31

1 Answers1

8

I had a similar issue and here's what I did...

For each foreign key column, I stored 2 values in handsontable; one for the id itself, which I set as a hidden column and the other is the user friendly readable text value as dropdowns.

Everytime the value of a dropdown is changed, I also change the corresponding hidden id. In my case I have a dropdown outside the handsontable as a filter which I use to map key/value pairs, but you could use Hashtables or anything else.

Now the code...

Handsontable config:

afterChange: function (changes, source) { AfterChange(changes, source); }

After change event (called everytime there is a change in the table):

function AfterChange(Changes, Source) {

    if (Source === 'loadData') {
        return; //don't save this change
    }
    var rowIndex = 0, columnID = 1, oldTextVal = 2, newTextVal = 3, ntv = '', nv = '';
    $(Changes).each(function () {
        if (this[columnID] === 'CategoryID') {
            // Do nothing...
            //To make sure nothing else happens when this column is set through below
        }
        else if (this[columnID] === 'CategoryName') {
            ntv = this[newTextVal];
            //This is where I do my mapping using a dropdown.
            nv = $('#CategoriesFilterDropdown option').filter(function () { return $(this).text() === ntv; }).val();
            //13 is my CategoryID column
            $container.handsontable('setDataAtCell', this[rowIndex], 13, nv);
        }
    });
    }
}

This way, you change the foreign keys as you and don't need to loop through it all before saving. It also makes it easy to send the table data as is back to server.

In summary,

  • The user interacts with CategoryName column (which is of type autocomplete).
  • The CatgoryID column is hidden to the user by setting the column width to 0 using the colWidths option of handsontable.
  • When the CategoryName field changes, use afterChange event to set the corresponding CategoryID column. In my case, I use a dropdown somewhere else on the page to map Name => ID, but you can use other means such as a hashtable.

I hope it makes sense...

PostureOfLearning
  • 3,403
  • 3
  • 23
  • 44
  • Thanks @PostureOfLearning, could you clarify the following: If I understand correctly the user interacts with the `CategoryName` column which is of type `autocomplete` and the external `dropdown/select` `#CategoriesFilterDropdown` is not visable to the user, but instead used to simplify the mapping process. Also, how do you hide the `CategoryID` column? Do you just use a `renderer` and set it css `visibility` property to `hidden`? – Chopo87 Jul 25 '13 at 09:15
  • 1
    @Chopo87, see the 'summary' I added. As my 'mapping tool' I use CategoriesFilterDropdown which is visible and located somewhere else on the page. I do this because I needed the dropdown visible for other purposes and didn't feel the need to duplicate the data. in your case you may want to use a hashtable to look up the IDs instead. – PostureOfLearning Jul 25 '13 at 11:32
  • Unfortunately this only works when there are no repeated `CategoryName` values in the drodpdown (with different IDs). Should be fine in most cases but not all. – Steven de Salas Jan 08 '14 at 02:13
  • 1
    @StevendeSalas, you are right, but why would you have a dropdown with multiple same display value that have different IDs behind the scene? The user wouldn't know which one they are selecting. – PostureOfLearning Jan 12 '14 at 09:48
  • You could also use `setDataAtRowProp()` to set your ID using the object property name, rather than the column index – Kurai Bankusu Nov 22 '15 at 05:13