saasufy-components 2.15.1 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/input-provider.js +7 -5
- package/model-input.js +10 -7
- package/package.json +1 -1
- package/utils.js +10 -3
package/README.md
CHANGED
|
@@ -356,6 +356,7 @@ Used for displaying and editing a single field of a model instance in real time.
|
|
|
356
356
|
- `type`: The type of the input component; can be `text`, `number`, `select`, `textarea` or `checkbox`.
|
|
357
357
|
- `placeholder`: Can be used to set the placeholder text on the inner input element.
|
|
358
358
|
- `consumers`: This allows you to connect this `model-input` to other elements on your page which share the same parent element. It takes a list of selectors with optional attributes to target. For example `.my-input:value` will find all elements with a `my-input` class and update their `value` attributes with the value of the `model-input` component in real-time. You can specify multiple selectors separated by commas such as `.my-input,my-div` - In this case, because attribute names are not specified, values will be injected into the `value` attribute (for input elements) or into the `innerHTML` property (for other kinds of elements). The default attribute/property depends on the element type.
|
|
359
|
+
- `provider-template`: A template string within which the `{{value}}` can be injected before passing to consumers.
|
|
359
360
|
- `show-error-message`: If this attribute is present, an error message will be displayed above the input if it fails to update the value.
|
|
360
361
|
- `options`: A comma-separated list of options to provide - This only works if the input type is `select`.
|
|
361
362
|
- `height`: Allows you to set the height of the inner `input` element programmatically.
|
|
@@ -426,7 +427,6 @@ Used for rendering a single model resource using a template. This is the single-
|
|
|
426
427
|
An input component which can pass data to other components (or HTML elements) via custom attributes.
|
|
427
428
|
A common use case for it is to pass user input to `collection-browser` or `model-viewer` components to then fetch data from Saasufy.
|
|
428
429
|
This component can be configured to provide its data to multiple components (consumers) via custom attributes.
|
|
429
|
-
Note that an `input-provider` only targets elements which are downstream from its parent element in the HTML hierarchy.
|
|
430
430
|
|
|
431
431
|
**Example usage**
|
|
432
432
|
|
|
@@ -446,6 +446,7 @@ Note that an `input-provider` only targets elements which are downstream from it
|
|
|
446
446
|
- `type`: The type of the input component; can be `text`, `number`, `select`, `textarea` or `checkbox`.
|
|
447
447
|
- `placeholder`: Can be used to set the placeholder text on the inner input element.
|
|
448
448
|
- `consumers`: This allows you to connect this `input-provider` to other elements on your page which share the same parent element. It takes a list of selectors with optional attributes to target. For example `.my-input:value` will find all elements with a `my-input` class and update their `value` attributes with the value of the `input-provider` component in real-time. You can specify multiple selectors separated by commas such as `.my-input,my-div` - In this case, because attribute names are not specified, values will be injected into the `value` attribute (for input elements) or into the `innerHTML` property (for other kinds of elements). The default attribute/property depends on the element type.
|
|
449
|
+
- `provider-template`: A template string within which the `{{value}}` can be injected before passing to consumers.
|
|
449
450
|
- `debounce-delay`: The delay in milliseconds to wait before triggering a change event. This is useful to batch multiple updates together (as is common when user is typing). Default is 800ms.
|
|
450
451
|
- `options`: A comma-separated list of options to provide - This only works if the input type is `select`.
|
|
451
452
|
- `height`: Allows you to set the height of the inner `input` element programmatically.
|
|
@@ -584,7 +585,14 @@ It's intended to be placed inside a `model-viewer`, `collection-browser` or `col
|
|
|
584
585
|
**Example usage**
|
|
585
586
|
|
|
586
587
|
```html
|
|
587
|
-
|
|
588
|
+
<if-group show-content="{{!!Product.isVisible}}">
|
|
589
|
+
<template slot="content">
|
|
590
|
+
<div>Name: {{Product.name}}</div>
|
|
591
|
+
<div>Description: {{Product.desc}}</div>
|
|
592
|
+
<div>Quantity: {{Product.qty}}</div>
|
|
593
|
+
</template>
|
|
594
|
+
<div slot="viewport"></div>
|
|
595
|
+
</if-group>
|
|
588
596
|
```
|
|
589
597
|
|
|
590
598
|
### switch-group
|
package/input-provider.js
CHANGED
|
@@ -135,20 +135,21 @@ class InputProvider extends HTMLElement {
|
|
|
135
135
|
|
|
136
136
|
let onInputChange = (event) => {
|
|
137
137
|
debounce(async () => {
|
|
138
|
+
let providerTemplate = this.getAttribute('provider-template');
|
|
138
139
|
if (event.target.value === this.lastValue) return;
|
|
139
140
|
if (inputElement.type === 'checkbox') {
|
|
140
141
|
let checked = !!inputElement.checked;
|
|
141
142
|
this.lastValue = checked;
|
|
142
|
-
updateConsumerElements(
|
|
143
|
+
updateConsumerElements(consumers, checked, providerTemplate);
|
|
143
144
|
return;
|
|
144
145
|
}
|
|
145
146
|
this.lastValue = event.target.value;
|
|
146
147
|
if (event.target.value === '') {
|
|
147
|
-
updateConsumerElements(
|
|
148
|
+
updateConsumerElements(consumers, '', providerTemplate);
|
|
148
149
|
} else {
|
|
149
150
|
let targetValue = inputElement.type === 'number' ?
|
|
150
151
|
Number(event.target.value) : event.target.value;
|
|
151
|
-
updateConsumerElements(
|
|
152
|
+
updateConsumerElements(consumers, targetValue, providerTemplate);
|
|
152
153
|
}
|
|
153
154
|
}, debounceDelay);
|
|
154
155
|
};
|
|
@@ -158,14 +159,15 @@ class InputProvider extends HTMLElement {
|
|
|
158
159
|
if (inputElement.type !== 'checkbox') {
|
|
159
160
|
onInputKeyUp = async (event) => {
|
|
160
161
|
debounce(async () => {
|
|
162
|
+
let providerTemplate = this.getAttribute('provider-template');
|
|
161
163
|
if (event.target.value === this.lastValue) return;
|
|
162
164
|
this.lastValue = event.target.value;
|
|
163
165
|
if (event.target.value === '') {
|
|
164
|
-
updateConsumerElements(
|
|
166
|
+
updateConsumerElements(consumers, '', providerTemplate);
|
|
165
167
|
} else {
|
|
166
168
|
let targetValue = inputElement.type === 'number' ?
|
|
167
169
|
Number(event.target.value) : event.target.value;
|
|
168
|
-
updateConsumerElements(
|
|
170
|
+
updateConsumerElements(consumers, targetValue, providerTemplate);
|
|
169
171
|
}
|
|
170
172
|
}, debounceDelay);
|
|
171
173
|
};
|
package/model-input.js
CHANGED
|
@@ -248,14 +248,15 @@ class ModelInput extends SocketConsumer {
|
|
|
248
248
|
|
|
249
249
|
updateInputElement(inputElement, fieldValue) {
|
|
250
250
|
let consumers = this.getAttribute('consumers');
|
|
251
|
+
let providerTemplate = this.getAttribute('provider-template');
|
|
251
252
|
if (inputElement.type === 'checkbox') {
|
|
252
253
|
let checked = !!fieldValue;
|
|
253
254
|
inputElement.checked = checked;
|
|
254
|
-
updateConsumerElements(
|
|
255
|
+
updateConsumerElements(consumers, checked, providerTemplate);
|
|
255
256
|
} else {
|
|
256
257
|
let defaultValue = this.getAttribute('default-value') || '';
|
|
257
258
|
inputElement.value = fieldValue == null ? defaultValue : fieldValue;
|
|
258
|
-
updateConsumerElements(
|
|
259
|
+
updateConsumerElements(consumers, inputElement.value, providerTemplate);
|
|
259
260
|
}
|
|
260
261
|
}
|
|
261
262
|
|
|
@@ -305,10 +306,11 @@ class ModelInput extends SocketConsumer {
|
|
|
305
306
|
let onInputChange = (event) => {
|
|
306
307
|
if (event.target.value === String(model.value[fieldName])) return;
|
|
307
308
|
debounce(async () => {
|
|
309
|
+
let providerTemplate = this.getAttribute('provider-template');
|
|
308
310
|
try {
|
|
309
311
|
if (inputElement.type === 'checkbox') {
|
|
310
312
|
let checked = !!inputElement.checked;
|
|
311
|
-
updateConsumerElements(
|
|
313
|
+
updateConsumerElements(consumers, checked, providerTemplate);
|
|
312
314
|
await model.update(fieldName, checked);
|
|
313
315
|
inputElement.classList.remove(errorStyleClass);
|
|
314
316
|
inputElement.classList.add(successStyleClass);
|
|
@@ -316,12 +318,12 @@ class ModelInput extends SocketConsumer {
|
|
|
316
318
|
return;
|
|
317
319
|
}
|
|
318
320
|
if (event.target.value === '') {
|
|
319
|
-
updateConsumerElements(
|
|
321
|
+
updateConsumerElements(consumers, '', providerTemplate);
|
|
320
322
|
await model.delete(fieldName);
|
|
321
323
|
} else {
|
|
322
324
|
let targetValue = inputElement.type === 'number' ?
|
|
323
325
|
Number(event.target.value) : event.target.value;
|
|
324
|
-
updateConsumerElements(
|
|
326
|
+
updateConsumerElements(consumers, targetValue, providerTemplate);
|
|
325
327
|
await model.update(fieldName, targetValue);
|
|
326
328
|
}
|
|
327
329
|
inputElement.classList.remove(errorStyleClass);
|
|
@@ -340,14 +342,15 @@ class ModelInput extends SocketConsumer {
|
|
|
340
342
|
if (inputElement.type !== 'checkbox' && inputElement.type !== 'select') {
|
|
341
343
|
onInputKeyUp = async (event) => {
|
|
342
344
|
debounce(async () => {
|
|
345
|
+
let providerTemplate = this.getAttribute('provider-template');
|
|
343
346
|
try {
|
|
344
347
|
if (event.target.value === '') {
|
|
345
348
|
await model.delete(fieldName);
|
|
346
|
-
updateConsumerElements(
|
|
349
|
+
updateConsumerElements(consumers, '', providerTemplate);
|
|
347
350
|
} else {
|
|
348
351
|
let targetValue = inputElement.type === 'number' ?
|
|
349
352
|
Number(event.target.value) : event.target.value;
|
|
350
|
-
updateConsumerElements(
|
|
353
|
+
updateConsumerElements(consumers, targetValue, providerTemplate);
|
|
351
354
|
await model.update(fieldName, targetValue);
|
|
352
355
|
}
|
|
353
356
|
inputElement.classList.remove(errorStyleClass);
|
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -232,8 +232,8 @@ export function renderTemplate(templateString, data, socket) {
|
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
export function updateConsumerElements(
|
|
236
|
-
if (
|
|
235
|
+
export function updateConsumerElements(consumers, value, template) {
|
|
236
|
+
if (consumers) {
|
|
237
237
|
let consumerParts = consumers.split(',')
|
|
238
238
|
.filter(part => part)
|
|
239
239
|
.map(part => {
|
|
@@ -242,8 +242,15 @@ export function updateConsumerElements(parentElement, consumers, value) {
|
|
|
242
242
|
})
|
|
243
243
|
.filter(([ selector, attributeName ]) => selector);
|
|
244
244
|
|
|
245
|
+
if (template) {
|
|
246
|
+
value = renderTemplate(
|
|
247
|
+
template,
|
|
248
|
+
{ value }
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
245
252
|
for (let [ selector, attributeName ] of consumerParts) {
|
|
246
|
-
let matchingElements =
|
|
253
|
+
let matchingElements = document.querySelectorAll(selector);
|
|
247
254
|
if (attributeName) {
|
|
248
255
|
for (let element of matchingElements) {
|
|
249
256
|
if (typeof value === 'boolean') {
|