Render items from store

This commit is contained in:
Josh Johnson 2016-04-04 14:43:22 +01:00
parent 174aa399c2
commit d8620f433f
5 changed files with 88 additions and 96 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,12 +1,17 @@
export const addItemToStore = (value, element, id) => { export const addItemToStore = (value, id) => {
return { return {
type: 'ADD_ITEM', type: 'ADD_ITEM',
value: value, value: value,
element: element,
id: id id: id
} }
}; };
export const unselectAllFromStore = () => {
return {
type: 'UNSELECT_ALL'
}
}
export const removeItemFromStore = (id) => { export const removeItemFromStore = (id) => {
return { return {
type: 'REMOVE_ITEM', type: 'REMOVE_ITEM',

View file

@ -2,7 +2,7 @@
import { createStore } from 'redux'; import { createStore } from 'redux';
import choices from './reducers/index.js'; import choices from './reducers/index.js';
import { addItemToStore, removeItemFromStore, selectItemFromStore } from './actions/index'; import { addItemToStore, removeItemFromStore, selectItemFromStore, unselectAllFromStore } from './actions/index';
import { hasClass, wrap, getSiblings, isType, strToEl } from './lib/utils.js'; import { hasClass, wrap, getSiblings, isType, strToEl } from './lib/utils.js';
@ -20,7 +20,6 @@ export class Choices {
constructor(options) { constructor(options) {
const fakeEl = document.createElement("fakeel"); const fakeEl = document.createElement("fakeel");
const userOptions = options || {}; const userOptions = options || {};
const store = createStore(choices);
const defaultOptions = { const defaultOptions = {
element: document.querySelector('[data-choice]'), element: document.querySelector('[data-choice]'),
disabled: false, disabled: false,
@ -44,7 +43,7 @@ export class Choices {
// Merge options with user options // Merge options with user options
this.options = this.extend(defaultOptions, userOptions || {}); this.options = this.extend(defaultOptions, userOptions || {});
this.store = store; this.store = createStore(choices);
this.initialised = false; this.initialised = false;
this.supports = 'querySelector' in document && 'addEventListener' in document && 'classList' in fakeEl; this.supports = 'querySelector' in document && 'addEventListener' in document && 'classList' in fakeEl;
@ -62,6 +61,7 @@ export class Choices {
// Bind methods // Bind methods
this.onKeyDown = this.onKeyDown.bind(this); this.onKeyDown = this.onKeyDown.bind(this);
this.onClick = this.onClick.bind(this); this.onClick = this.onClick.bind(this);
this.renderItems = this.renderItems.bind(this);
this.init(); this.init();
} }
@ -183,12 +183,11 @@ export class Choices {
// All is good, add // All is good, add
if(canAddItem) { if(canAddItem) {
this.addItem(this.list, value); this.addItem(value);
this.updateInputValue(value); this.updateInputValue(value);
this.clearInput(this.element); this.clearInput(this.element);
} }
} }
} }
}; };
@ -212,7 +211,7 @@ export class Choices {
// If editing the last item is allowed and there is a last item and // If editing the last item is allowed and there is a last item and
// there are not other selected items (minus the last item), we can edit // there are not other selected items (minus the last item), we can edit
// the item value. Otherwise if we can remove items, remove all items // the item value. Otherwise if we can remove items, remove all items
if(this.options.editItems && lastItem && selectedItems.length === 1) { if(this.options.editItems && lastItem && selectedItems.length === 0) {
this.input.value = lastItem.innerHTML; this.input.value = lastItem.innerHTML;
this.removeItem(lastItem); this.removeItem(lastItem);
} else { } else {
@ -269,16 +268,12 @@ export class Choices {
selectItem(item) { selectItem(item) {
let id = item.getAttribute('data-choice-id'); let id = item.getAttribute('data-choice-id');
item.classList.add('is-selected');
this.store.dispatch(selectItemFromStore(id, true)); this.store.dispatch(selectItemFromStore(id, true));
console.log(this.store.getState());
} }
unselectItem(item) { unselectItem(item) {
let id = item.getAttribute('data-choice-id'); let id = item.getAttribute('data-choice-id');
item.classList.remove('is-selected');
this.store.dispatch(selectItemFromStore(id, false)); this.store.dispatch(selectItemFromStore(id, false));
console.log(this.store.getState());
} }
selectAll(items) { selectAll(items) {
@ -307,7 +302,7 @@ export class Choices {
this.element.value = this.valueArray.join(this.options.delimiter); this.element.value = this.valueArray.join(this.options.delimiter);
} }
addItem(parent, value) { addItem(value) {
if (this.options.debug) console.debug('Add item'); if (this.options.debug) console.debug('Add item');
let passedValue = value; let passedValue = value;
@ -322,25 +317,20 @@ export class Choices {
passedValue = passedValue + this.options.appendValue.toString(); passedValue = passedValue + this.options.appendValue.toString();
} }
// Generate unique id
let id = this.store.getState().length + 1; let id = this.store.getState().length + 1;
// Create new list element
let item = strToEl(`<li class="choices__item" data-choice-id=${id}>${passedValue}</li>`);
// Append it to list
parent.appendChild(item);
// Run callback if it is a function // Run callback if it is a function
if(this.options.callbackOnAddItem){ if(this.options.callbackOnAddItem){
if(isType('Function', this.options.callbackOnAddItem)) { if(isType('Function', this.options.callbackOnAddItem)) {
this.options.callbackOnAddItem(item, value); this.options.callbackOnAddItem(id, value);
} else { } else {
console.error('callbackOnAddItem: Callback is not a function'); console.error('callbackOnAddItem: Callback is not a function');
} }
} }
this.store.dispatch(addItemToStore(passedValue, item, id)); this.store.dispatch(addItemToStore(passedValue, id));
console.log(this.store.getState()); this.store.dispatch(unselectAllFromStore(passedValue, id));
} }
removeItem(item) { removeItem(item) {
@ -351,7 +341,6 @@ export class Choices {
let id = item.getAttribute('data-choice-id'); let id = item.getAttribute('data-choice-id');
let value = item.innerHTML; let value = item.innerHTML;
item.parentNode.removeChild(item);
// Run callback // Run callback
if(this.options.callbackOnRemoveItem){ if(this.options.callbackOnRemoveItem){
@ -363,7 +352,6 @@ export class Choices {
} }
this.store.dispatch(removeItemFromStore(id)); this.store.dispatch(removeItemFromStore(id));
console.log(this.store.getState());
} }
removeAll(items) { removeAll(items) {
@ -380,7 +368,7 @@ export class Choices {
init() { init() {
if (!this.supports) console.error('init: Your browser doesn\'nt support shit'); if (!this.supports) console.error('init: Your browser doesn\'nt support shit');
this.initialised = true; this.initialised = true;
this.render(this.element); this.renderInput(this.element);
} }
renderTextInput() { renderTextInput() {
@ -434,7 +422,7 @@ export class Choices {
if (this.element.value !== '') { if (this.element.value !== '') {
// Add any preset values // Add any preset values
this.valueArray.forEach((value) => { this.valueArray.forEach((value) => {
this.addItem(this.list, value); this.addItem(value);
}); });
} }
@ -443,13 +431,32 @@ export class Choices {
this.list.addEventListener('click', this.onClick); this.list.addEventListener('click', this.onClick);
} }
renderItems(){
let items = this.store.getState();
render() { this.list.innerHTML = '';
items.forEach((item) => {
if(item.active) {
// Create new list element
let listItem = strToEl(`<li class="choices__item ${ item.selected ? 'is-selected' : '' }" data-choice-id="${item.id}" data-choice-selected="${item.selected}">${item.value}</li>`);
// Append it to list
this.list.appendChild(listItem);
}
});
console.log(items);
}
renderInput() {
if (this.options.debug) console.debug('Render'); if (this.options.debug) console.debug('Render');
switch (this.element.type) { switch (this.element.type) {
case "text": case "text":
this.renderTextInput(); this.renderTextInput();
this.store.subscribe(this.renderItems);
this.renderItems();
break; break;
case "select-one": case "select-one":
// this.renderSelectInput(); // this.renderSelectInput();
@ -461,7 +468,6 @@ export class Choices {
this.renderTextInput(); this.renderTextInput();
break; break;
} }
} }
destroy() { destroy() {
@ -482,36 +488,37 @@ export class Choices {
let choices1 = new Choices({ let choices1 = new Choices({
element : input1, element : input1,
// delimiter: ' ', // delimiter: ' ',
// maxItems: 5, editItems: true,
// callbackOnRemoveItem: function(value) { maxItems: 5,
// console.log(value); callbackOnRemoveItem: function(value) {
// }, console.log(value);
// callbackOnAddItem: function(item, value) { },
// console.log(item, value); callbackOnAddItem: function(item, value) {
// } console.log(item, value);
}
}); });
// let choices2 = new Choices({ let choices2 = new Choices({
// element : input2, element : input2,
// allowDuplicates: false, allowDuplicates: false,
// editItems: true, editItems: true,
// }); });
// let choices3 = new Choices({ let choices3 = new Choices({
// element : input3, element : input3,
// allowDuplicates: false, allowDuplicates: false,
// editItems: true, editItems: true,
// regexFilter: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ regexFilter: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
// }); });
// let choices4 = new Choices({ let choices4 = new Choices({
// element : input4, element : input4,
// addItems: false addItems: false
// }); });
// let choices5 = new Choices({ let choices5 = new Choices({
// element: input5, element: input5,
// prependValue: 'item-', prependValue: 'item-',
// appendValue: `-${Date.now()}` appendValue: `-${Date.now()}`
// }); });
})(); })();

View file

@ -5,11 +5,18 @@ const choices = (state = [], action) => {
return [...state, { return [...state, {
id: parseInt(action.id), id: parseInt(action.id),
value: action.value, value: action.value,
element: action.element,
active: true, active: true,
selected: false selected: false
}]; }];
case 'UNSELECT_ALL':
return state.map((item) => {
if(item.selected) {
item.selected = false;
}
return item;
});
case 'REMOVE_ITEM': case 'REMOVE_ITEM':
// Set item to inactive // Set item to inactive
return state.map((item) => { return state.map((item) => {

View file

@ -6,50 +6,23 @@
<link rel="stylesheet" href="assets/styles/css/choices.css"> <link rel="stylesheet" href="assets/styles/css/choices.css">
</head> </head>
<body> <body>
<label for="1">Text input with no values and a limit of 5 items</label> <div class="container">
<input id="1" type="text" data-choice value="preset-1, preset-2"> <label for="1">Text input with no values and a limit of 5 items</label>
<!-- <input id="1" type="text" data-choice value="preset-1, preset-2">
<label for="2">Text input with preset values, custom classes and a placeholder. No duplicate values allowed</label>
<input id="2" type="text" data-choice value="preset-1, preset-2" placeholder="This is a placeholder" class="custom class">
<label for="3">Text input that only allows email addresses</label> <label for="2">Text input with preset values, custom classes and a placeholder. No duplicate values allowed</label>
<input id="3" type="text" data-choice placeholder="This is a placeholder"> <input id="2" type="text" data-choice value="preset-1, preset-2" placeholder="This is a placeholder" class="custom class">
<label for="4">Text input that disables adding items</label> <label for="3">Text input that only allows email addresses</label>
<input id="4" type="text" data-choice value="josh@joshuajohnson.co.uk, joe@bloggs.co.uk" placeholder="This is a placeholder"> <input id="3" type="text" data-choice placeholder="This is a placeholder">
<label for="5">Text input that prepends and appends a value to each item</label> <label for="4">Text input that disables adding items</label>
<input id="5" type="text" data-choice value="preset-1, preset-2" placeholder="This is a placeholder"> --> <input id="4" type="text" data-choice value="josh@joshuajohnson.co.uk, joe@bloggs.co.uk" placeholder="This is a placeholder">
<!-- <label for="3">Select input with two options</label> <label for="5">Text input that prepends and appends a value to each item</label>
<select id="3" name="3" data-choice> <input id="5" type="text" data-choice value="preset-1, preset-2" placeholder="This is a placeholder">
<option value="Value 1">Value 1</option>
<option value="Value 2">Value 2</option>
<option value="Value 3">Value 3</option>
<option value="Value 4">Value 4</option>
<option value="Value 5">Value 5</option>
<option value="Value 6">Value 6</option>
</select>
<select id="4" name="4" data-choice> </div>
<optgroup label="Group 1">
<option value="Value 1">Value 1</option>
<option value="Value 2">Value 2</option>
<option value="Value 3">Value 3</option>
</optgroup>
<optgroup label="Group 2">
<option value="Value 4">Value 4</option>
<option value="Value 5">Value 5</option>
<option value="Value 6">Value 6</option>
</optgroup>
</select> -->
<!-- <label for="4">Multiple select input with two options</label>
<select id="4" name="4" data-choice multiple>
<option value="Value 1">Value 1</option>
<option value="Value 2">Value 2</option>
</select>
-->
<script src="assets/scripts/dist/bundle.js"></script> <script src="assets/scripts/dist/bundle.js"></script>
</body> </body>
</html> </html>