Working Example
Key
Input: #key
Key Value Table
Value
Input: #value
Add To Table
Button: #addToTable
Text: #error
Table: #kvTable
Key | Value |
---|
Key Drop Down
DropDown: #keyDropdown
Value Drop Down
DropDown: #valueDropdown
Overview
This example shows you how to create a unique drop down list from a table of data where each column may have duplicate entries.
Use:
-
Enter a key value pair in the fields provided at the top of the page.
-
Click on Add to add the Key-Value page to the Table.
-
Click on either drop down to see the sorted and unique list of entries presented in the drop down list
What's happening:
When a new key value pair is entered it is checked against a data collection connected to the page via a dataset $w('#kvPairsDataset'). If the specific key value pair already exists then it is rejected. Otherwise the pair is added to the data collection using the dataset setFieldValues() and save() functions.
After the array is updated each dropdown is populated by calling refreshDropDowns(). This cycles through a list (array) of drop down names mapped to the element keys pulled from the dataset. The dropdown names are structured to allow an array to process them
'#<keyName>Dropdown'. Each drop down keyName is passed to the function uniqueListForColumn(). The result of the call to uniqueListForColumn(), dropDownList, is then mapped into the object array format expected by the $w.DropDown element options parameter using the dropDownList item as both the 'label' for the dropdown and the 'value'.
When uniqueListForColumn() is called it checks to make sure that the columnName is valid by calling the Array some() function to look for any key value pair containing the columnName. If one exists it then cycles through each record using the Array forEach() function and extracts the value for the property that matches the columnName passed as an argument. If this value doesn't exist in the results array then it is pushed onto the results array. This ensures that the results array only has unique values. The results array is then sorted as it is returned from the function.
Page Code
// For full API documentation, including code examples, visit http://wix.to/94BuAAs
// onReady - initialises the table with any pre existing values.
// Because it uses a dataset it needs to wait for the dataset to be ready
$w.onReady(function () {
//set up page defaults
clearErrorMessage();
// Wait for the dataset to load
$w('#kvPairsDataset').onReady(() => {
loadTable();
});
});
// clearKeyValuePair - convenience function to clear the input fields
function clearKeyValuePair() {
$w('#key').value = '';
$w('#value').value = '';
}
// clearTable - Convenience function to clear the table display
function clearTable() {
$w('#kvTable').rows = [];
}
// loadTable - retrieves all saved dataset items and uses them to update the table and dropdown
function loadTable () {
clearTable();
return refreshKVPairs(['key', 'value'])
.then((kvPairs) => {
refreshTable(kvPairs);
refreshDropDowns(kvPairs);
})
}
// uniqueListForColumn - generates an array of unique values from a given column name
// kvPairs is the dataset we have extracted to display as an array of objects
// columnName is the name of the key in each kvPairs record that we want in our unique list
function uniqueListForColumn(kvPairs, columnName) {
let result = [];
// If there is at least one kvPair with the column name (key name in the object) then we can generate a list
// Uses Object.keys to grab the array of column names from each kvPairs row element returning true if a key matches
if (kvPairs.some(rowElement => Object.keys(rowElement).indexOf(columnName) !== -1)) {
// Cycle through each rowItem in the kvPairs records we were given and extract the column values we have been asked for
kvPairs.forEach((rowItem) => {
let columnValue = rowItem[columnName];
// We need the list to be unique so if we have this value already then ignore it
if (columnValue && result.indexOf(columnValue) === -1) {
// We can add this as we don't already have it
result.push(columnValue);
}
});
}
return result.sort();
}
// updateTable - adds the key value pair in the input fields if they don't already exist in the dataset
// The function calls refreshKVPairs() to get the current set of data in our dataset.
// It then verifies that the key value pair is not in the set.
// It then updates the dataset with a new record and refreshes the table view and the drop down list
function updateTable() {
let key = $w('#key').value;
let value = $w('#value').value;
if (key.length === 0 || value.length === 0) {
setErrorMessage("Please enter a Key and a Value");
} else {
// Reload the kvPairs from our dataset
refreshKVPairs(['key', 'value'])
.then((datasetRecords) => {
// We should now have a list of the key and value columns from the dataset
if (!keyValuePairIsNew(datasetRecords, key, value)) {
clearKeyValuePair();
throw Error("Key Value Pair already exists");
}
// This set is new so add it to the dataset
return updateKVPairs(key, value);
})
.then(() => {
// Dataset save succeeded so update the views
loadTable();
})
.catch(err => {
setErrorMessage(err.message);
});
}
}
// updateKVPairs - forces a new dataset item to be created. Adds the new values and saves the new item.
// The function returns the promise returned by the dataset save function.
function updateKVPairs(key, value) {
return $w('#kvPairsDataset').new()
.then(() => {
$w('#kvPairsDataset').setFieldValues({'key':key, 'value':value});
return $w('#kvPairsDataset').save();
})
}
// refreshDropDowns - cycles through the dropdowns on the page generating a unique list for each drop down
function refreshDropDowns(kvPairs) {
let dropDowns = ['key', 'value'];
dropDowns.forEach(dropDown => {
let dropDownList = uniqueListForColumn(kvPairs, dropDown);
// The drop down list is a simple array of strings. We need to map it into an options
//object array required by the dropDown element
$w('#'+dropDown+'Dropdown').options = dropDownList.map(listItem => {return {'label':listItem, 'value':listItem}});
});
}
// keyValuePairIsNew - Scans the given records list (array of objects) for a matching key value pair.
// Returns a boolen that is true if no match is found, false otherwise
function keyValuePairIsNew(records, key, value) {
// Return the result of finding and index or not. Not finding an index (-1) results in a true result
return records.findIndex((arrayItem) => {
//Test each element in the array to see if the kv pair already exists
return (arrayItem.key === key && arrayItem.value === value);
}) === -1;
}
// refreshKVPairs - loads all records in the dataset and then filters it to limit
// the results to the columns requested in the arguments array
function refreshKVPairs(columnNames) {
// We want all records so we will scope the get to include totalCount items
return $w('#kvPairsDataset').getItems(0, $w('#kvPairsDataset').getTotalCount())
.then((kvRecords) => {
let result = [];
// We have a successful result. Use the array map function to filter the dataset
result = kvRecords.items.map ( item => {
let mapRecord = {};
// Cycle through the requested columnNames saving the values we find in the results array
for (var columnName of columnNames) {
// Grab the value if it exists
let columnValue = item[columnName];
if (columnValue) {
// Value exists so add it to the results.
mapRecord[columnName] = columnValue;
}
}
return mapRecord;
})
// Return the result as a promise so it can be used in futher promise processing
return Promise.resolve(result);
})
}
// refreshTable - takes an array of objects containing label and value key value pairs and loads the table element
function refreshTable(kvPairs) {
$w('#kvTable').rows = kvPairs;
}
// setErrorMessage - convenience function to show an error
function setErrorMessage(message) {
$w('#error').text = message;
}
// clearErrorMessage - clears the error message
function clearErrorMessage() {
$w('#error').text = '';
}
// value_change - value change handler used to clear an error message if a new value is added
export function value_change(event) {
clearErrorMessage();
}
// key_change - key change handler used to clear an error message if a new value is added
export function key_change(event) {
clearErrorMessage();
}
// addToTable_click - click handler used to examine the input fields and update the table and download elements
export function addToTable_click(event) {
updateTable();
}