Updated way of handling selected items by using writable store and context

This commit is contained in:
Conor Mack 2020-02-27 15:45:28 +00:00
parent d88d377f5f
commit fa199bdacf
6 changed files with 120 additions and 54 deletions

View File

@ -18,18 +18,16 @@
let instance = null let instance = null
let checkbox = null let checkbox = null
let context = null let context = _bb.getContext("BBMD:input:context")
onMount(() => { onMount(() => {
context = _bb.getContext("BBMD:input:context")
if (!!checkbox) { if (!!checkbox) {
instance = new MDCCheckbox(checkbox) instance = new MDCCheckbox(checkbox)
instance.indeterminate = indeterminate instance.indeterminate = indeterminate
if (context !== "list-item") { if (context !== "list-item") {
//TODO: Fix this connected to Formfield context issue //TODO: Fix this connected to Formfield context issue
// let fieldStore = _bb.getContext("BBMD:field-element") let fieldStore = _bb.getContext("BBMD:field-element")
// fieldStore.setInput(instance) fieldStore.setInput(instance)
} }
} }
}) })

View File

@ -0,0 +1,54 @@
import { writable } from "svelte/store";
function createItemsStore(componentOnSelect) {
const { subscribe, set, update } = writable([]);
function addItem(item) {
update(items => {
return [...items, item]
})
if (componentOnSelect) {
componentOnSelect();
}
}
function addSingleItem(item) {
set([item])
if (componentOnSelect) {
componentOnSelect();
}
}
function removeItem(itemId) {
update(items => {
let index = getItemIdx(items, itemId)
items.splice(index, 1);
return items;
})
if (componentOnSelect) {
componentOnSelect();
}
}
function clearItems() {
set([]);
if (componentOnSelect) {
componentOnSelect();
}
}
function getItemIdx(items, itemId) {
return items.findIndex(i => i._id === itemId);
}
return {
subscribe,
addItem,
addSingleItem,
removeItem,
clearItems,
getItemIdx
}
}
export default createItemsStore

View File

@ -1,10 +1,13 @@
<script> <script>
import { onMount, getContext } from "svelte" import { onMount, getContext, setContext } from "svelte"
import { MDCList } from "@material/list" import { MDCList } from "@material/list"
import createItemsStore from "../Common/ItemStore.js"
import { MDCRipple } from "@material/ripple" import { MDCRipple } from "@material/ripple"
import ListItem from "./ListItem.svelte" import ListItem from "./ListItem.svelte"
import ClassBuilder from "../ClassBuilder.js" import ClassBuilder from "../ClassBuilder.js"
let selectedItems
export let _bb export let _bb
const cb = new ClassBuilder("list", ["one-line"]) const cb = new ClassBuilder("list", ["one-line"])
@ -17,34 +20,32 @@
export let variant = "two-line" export let variant = "two-line"
export let inputElement = null export let inputElement = null
let selectedItems = [] let selectedItemsStore
//TODO: Try managing selected list items with a store that is passed into context. This way can check within the component whether list item is selected to not selecteds instead of managing from internal state which is not feasible
function handleSelected(item) {
let idx = selectedItems.findIndex(i => i._id === item._id)
if (idx > -1) {
selectedItems.splice(idx, 1)
selectedItems = selectedItems
} else {
if (singleSelection) {
selectedItems = [item]
} else {
selectedItems = [...selectedItems, item]
}
}
}
//See todo above
_bb.setContext("BBMD:list:selectItem", handleSelected)
let role = "listbox" let role = "listbox"
function createOrAcceptItemStore() {
let store = _bb.getContext("BBMD:list:selectItemStore")
if (!!store) {
selectedItemsStore = store
} else {
selectedItemsStore = createItemsStore(() => onSelect($selectedItemsStore))
_bb.setContext("BBMD:list:selectItemStore", selectedItemsStore)
}
}
onMount(() => { onMount(() => {
_bb.setContext("BBMD:list:props", { inputElement, variant }) createOrAcceptItemStore()
_bb.setContext("BBMD:list:props", {
inputElement,
variant,
singleSelection,
})
if (!!list) { if (!!list) {
if (!inputElement) {
instance = new MDCList(list) instance = new MDCList(list)
instance.singleSelection = singleSelection instance.singleSelection = singleSelection
if (!inputElement) {
instance.listElements.map(element => new MDCRipple(element)) instance.listElements.map(element => new MDCRipple(element))
} }
} }

View File

@ -1,5 +1,5 @@
<script> <script>
import { onMount } from "svelte" import { onMount, getContext } from "svelte"
import { Radiobutton } from "../Radiobutton" import { Radiobutton } from "../Radiobutton"
import { Checkbox } from "../Checkbox" import { Checkbox } from "../Checkbox"
import ClassBuilder from "../ClassBuilder.js" import ClassBuilder from "../ClassBuilder.js"
@ -12,6 +12,8 @@
let _id let _id
let listProps = null let listProps = null
let selectedItems
export let _bb export let _bb
export let value = null export let value = null
@ -25,24 +27,11 @@
let role = "option" let role = "option"
function handleClick() {
if (!disabled) {
const selectItem = _bb.getContext("BBMD:list:selectItem")
selected = !selected
selectItem({
_id,
value,
text,
secondaryText,
selected,
disabled,
})
}
}
onMount(() => { onMount(() => {
_id = shortid.generate() _id = shortid.generate()
selectedItems = _bb.getContext("BBMD:list:selectItemStore")
listProps = _bb.getContext("BBMD:list:props") listProps = _bb.getContext("BBMD:list:props")
let context = _bb.getContext("BBMD:list:context") let context = _bb.getContext("BBMD:list:context")
@ -51,15 +40,41 @@
} }
}) })
function handleClick() {
let item = {
_id,
value,
text,
secondaryText,
selected,
disabled,
}
if (!disabled) {
if (
listProps.singleSelection ||
listProps.inputElement === "radiobutton"
) {
selectedItems.addSingleItem(item)
} else {
let idx = selectedItems.getItemIdx($selectedItems, _id)
if (idx > -1) {
selectedItems.removeItem(_id)
} else {
selectedItems.addItem(item)
}
}
}
}
$: if (listProps && !!listProps.inputElement) { $: if (listProps && !!listProps.inputElement) {
_bb.setContext("BBMD:input:context", "list-item") _bb.setContext("BBMD:input:context", "list-item")
} }
$: shouldSel = selected && !listProps $: isSelected =
$: console.log("Should Select", selected) $selectedItems && selectedItems.getItemIdx($selectedItems, _id) > -1
$: modifiers = { $: modifiers = {
selected: selected && (!listProps || !listProps.inputElement), selected: isSelected && (!listProps || !listProps.inputElement),
disabled, disabled,
} }
$: props = { modifiers } $: props = { modifiers }
@ -84,9 +99,9 @@
{#if listProps} {#if listProps}
{#if listProps.inputElement === 'radiobutton'} {#if listProps.inputElement === 'radiobutton'}
<Radiobutton checked={selected} {disabled} {_bb} /> <Radiobutton checked={isSelected} {disabled} {_bb} />
{:else if listProps.inputElement === 'checkbox'} {:else if listProps.inputElement === 'checkbox'}
<Checkbox checked={selected} {disabled} {_bb} /> <Checkbox checked={isSelected} {disabled} {_bb} />
{/if} {/if}
{:else if trailingIcon} {:else if trailingIcon}
<!-- TODO: Adapt label to accept class prop to handle this. Context is insufficient --> <!-- TODO: Adapt label to accept class prop to handle this. Context is insufficient -->

View File

@ -23,9 +23,8 @@
if (!!radiobtn) { if (!!radiobtn) {
instance = new MDCRadio(radiobtn) instance = new MDCRadio(radiobtn)
if (context !== "list-item") { if (context !== "list-item") {
//TODO: Fix this connected to Formfield context issue, _bb not binding properly let fieldStore = _bb.getContext("BBMD:field-element")
// let fieldStore = _bb.getContext("BBMD:field-element") fieldStore.setInput(instance)
// fieldStore.setInput(instance)
} }
} }
}) })

View File

@ -118,8 +118,7 @@ export const props = {
List: { List: {
_component: "@budibase/materialdesign-components/List", _component: "@budibase/materialdesign-components/List",
variant: "two-line", variant: "two-line",
inputElement: "radiobutton", singleSelection: false,
singleSelection: true,
onSelect: selected => console.log(selected), onSelect: selected => console.log(selected),
_children: [ _children: [
{ {