muonw / muonw-powertable

▦ PowerTable is a Svelte component that turns JSON data into an interactive HTML table. Inspired by DataTables. Powered by Svelte.
https://muonw.github.io/muonw-powertable/
Other
218 stars 13 forks source link

Link cell value to a function #19

Closed haenf closed 1 year ago

haenf commented 1 year ago

Hi @muonw I can easily get very nice results with PowerTable, but now I am stuck on something. I hope you can help me (again :-). I want some cell values to be a link to activate a simple modal eding facility (current value, input: new value, ok/cancel). To make the link I followed your recipe in Comment #6 on cell formatting.

In the PowerTable component:

let ptOptions = {
    userFunctions: {
        customParse: parsingFunctions
    },
    ...,
    }
}

function parsingFunctions(pageData) {
    pageData = setCellStyle(pageData);
    pageData = makeLinkedValue(pageData);
    return pageData;
}

...

function makeLinkedValue(pageData) {
    pageData.forEach(row => {
        for (let i = 0; i < searchHeaders.length; i++) {
           ...
           if (cellValue === searchTerm) {   
                row[searchHeaders[i]] = 
                   `<a href="#" onclick={editCell()}>${row[searchHeaders[i]]}</a>`;
            }
        }
    }); 
    return pageData;
}

I also tried:

`<a href="javascript:editCell()">${row[searchHeaders[i]]}</a>`

and

`<span class="ref" on:click={editCell()}>${row[searchHeaders[i]]}</span>`

In ptInstructs the relevant columns are set to 'unsafe-html'.

The function editCell() looks like (very simple, for testing):

function editCell() {
    console.log('edit this cell');
}

I tested with putting the function in the PowerTable component, and as an altrnative in the parent, following Stephane Vanraes recipe in https://stackoverflow.com/questions/68134909/svelte-use-function-from-a-parent-component

None of the combinations worked. The link itself shows fine, but linking to the function doesn't work. The "span class="ref"" solution did nothing at all, and both "a href" lines resulted in an "Uncaught ReferenceError: editCell is not defined".

Do you have an idea how I have to solve this?

muonw-public commented 1 year ago

Have you tried calling the function without parentheses? In version 2.0.0 you can't include Svelte code in pageData, but in general in Svelte you would want to use either on:click={functionName} (without parentheses), or if you need more flexibility, on:click={() => functionName()}

haenf commented 1 year ago

None of the options below worked...

These had no effect at all:

`<a href="#" on:click={editCell()}>${row[$userSelections['searchHeaders'][i]]}</a>`;
`<a href="#" on:click={editCell}>${row[$userSelections['searchHeaders'][i]]}</a>`;

These gave a message in the console:

`<a href="javascript:editCell()">${row[$userSelections['searchHeaders'][i]]}</a>`

console:
"Uncaught ReferenceError: editCell is not defined"
<anonymous> javascript:editCell():1

`<a href="javascript:editCell">${row[$userSelections['searchHeaders'][i]]}</a>`

console:
"Uncaught ReferenceError: editCell is not defined"
<anonymous> javascript:editCell:1

`<a href="#" onclick="editCell">${row[$userSelections['searchHeaders'][i]]}</a>`

console:
"Uncaught ReferenceError: editCell is not defined"
onclick http://localhost:4080/tableeditor:1

`<a href="#" onclick="editCell()">${row[$userSelections['searchHeaders'][i]]}</a>`

console:
"Uncaught ReferenceError: editCell is not defined"
onclick http://localhost:4080/tableeditor:1

Note: "tableeditor" is the parent of the PowerTable component.

Is there another possibility? If not, I guess I have to use the on:rowClicked option and select the editable cells from my source tables... Or is there a way to infer the column in which is clicked?

muonw-public commented 1 year ago

I see the problem now. You're trying to access a Svelte function from the global scope. One approach is to add your function to the window object:

window.editCell = () => {
    console.log('edit this cell');
}

A more sophisticated approach would be to add support for Svelte components / slots in userFunctions (https://github.com/muonw/powertable/issues/9#issuecomment-1328125279).

haenf commented 1 year ago

I took your first approach and it works fine:

pageData.forEach(row => {
    ...
    let idInt = row.__PT_ID__;            // the row number
    let paramStr = '`' + idInt.toString();
    paramStr = paramStr + 
        ' | ' +
        searchHeaders'[i] +           // the property
        ' | ' +
        searchTerm + '`';             // the cell value to be edited

    row[$userSelections['searchHeaders'][i]] = 
    `<a href="#" onclick="editCell(`+paramStr+`)">${row[searchHeaders[i]]}</a>`
}

window.editCell = (cellData) => {
    let data = cellData.split(' | ');
    ptData[data[0]][data[1] = some new value
}

The "some new value" comes from user input in a modal.

The biggest struggle (well, some trying) was finding out how to apply the backticks: around the paramStr and in the a-href (4x).

Now I can control exactly which cells in a table are in a certain context accessible for editing - that was what I was looking for.

Thank you again for your help!