ngx-input-flow
TypeScript icon, indicating that this package has built-in type declarations

1.3.0 • Public • Published

ngx-input-flow

Fast & smooth list input for Angular

build status code coverage

npm package license

No more 'add' or 'remove' buttons.
Create multiple elements just by tabbing through the controls.
Remove empty elements automatically.

ngx-input-flow demo

Installation

npm install --save ngx-input-flow

Usage

Import the module:

import { InputFlowModule } from 'ngx-input-flow';
 
@NgModule({
  imports: [
    // ...
    InputFlowModule,
  ],
  // ...
})
export class MyModule {}

Use the ngx-input-flow directives in the template of your component:
(this example assumes the component has a persons property)

<table [(ngxInputFlow)]="persons" <!-- 1 -->
       #input="ngxInputFlow"> <!-- 2 -->
  <tr *ngFor="let person of input.flow()" <!-- 3 -->
      [ngxInputFlowModel]="person"> <!-- 4 -->
    <td>
      <input type="text" name="name" [(ngModel)]="person.name"> <!-- 5 -->
    </td>
    <td>
      <input type="checkbox" name="invited" [(ngModel)]="person.invited"> <!-- 6 -->
    </td>
  </tr>
</table>
  1. Two-way bind the array that stores the elements that are to be edited.
  2. Bind the ngxInputFlow directive to the template variable input.
  3. Bind ngForOf to input.flow() instead of the array itself.
  4. Use ngxInputFlowModel to monitor changes to each element.
  5. Two-way bind ngModel as usual.
  6. Other input types work as well!

You can find some more examples in the e2e folder that is used for end-to-end tests.

Configuration options

ngxInputFlow options

Input Type Default
checkElements 'None' | 'New' | 'All' 'None'
trackBy TrackByFunction undefined
emptyWhen any => boolean item => Object.values(item).every(val => !val);
emptyItem () => any () => ({})

checkElements determines which elements of the array will be checked for emptiness during every change detection cycle. Discovered empty elements will be removed automatically. This does not affect the checks on user input, which are triggered by the ngxInputFlowModel directive. Instead, it allows for additional checks in case the array is modified or replaced externally (i.e. not by user input).
'None' (the default) disables all checks. It is recommended you ensure that no empty elements are inserted into the array from your program code to avoid annoying the user with intermediate empty elements.
'New' checks only elements that have been added since the last change detection cycle.
'All' checks the complete array every time. This is the least performant option.

trackBy should be used if you set checkElements to 'New' and your ngFor has a trackBy function as well. By passing the same function that ngFor also gets, you make sure that ngx-input-flow checks elements for emptiness in the same way ngFor checks them to determine which elements need to be updated.

emptyWhen is a function that determines whether an elements is considered empty. It takes the element as its only parameter. It returns true if the element is empty and false if it is not. The default considers elements empty if they have no truthy properties.

emptyItem is a function that supplies new elements to be used as trailing empty elements for the user to modify. If the user edits them and they become non-empty, they will be appended to the array itself. The default supplies empty objects ({}).

ngxInputFlowModel options

Input Type Default
focusDebounce number 500

focusDebounce specifies the delay after the last focus event before the array is checked for elements that were left empty and those are removed. A too low value can cause trouble for mouse users if they clear one element and then click on a subsequent one, because the empty element could be removed and cause all subsequent inputs to change its position (e.g. slide up), including the one the user is currently clicking.
The directive makes sure the currently focused element is never checked.
When using multiple ngxInputFlowModel inside a ngxInputFlow directive, those may be assigned different focusDebounce values. If subsequent focus events are detected by ngxInputFlowModel instances with different focusDebounce values, only the last value will be used to compute the delay. Note that if a focusout is detected by a ngxInputFlowModel with the focusDebounce set to 0, checks will be performed immediately, even if another instance with a higher value receives focus immediately after.

FAQ

Q: How do I use this within a form?
A: A variable number of form controls is problematic, because every control needs to have a unique name. You'd probably be best off excluding the controls from the form management by declaring it standalone:

[ngModelOptions]="{ standalone: true }"

Q: Can I put ngxInputFlow and ngxInputFlowModel on the same element?
A: No, ngxInputFlow needs to be above the *ngFor element and ngxInputFlowModel needs to be on or below it. If you move ngxInputFlow down to the *ngFor element, you cannot access input.flow() anymore. If you move ngxInputFlowModel above the *ngFor, you cannot access the current element anymore.

Q: I don't want intermediate items to disappear when the user empties them. How can I turn this off?
A: From 1.1.0 onwards, you can use ngxInputFlowModel without binding the array element to it. That way, only the flow (tail of array) checks are performed and intermediate items are left as-is.
Also, in this use case, the answer to the previous question becomes yes, since you can now move ngxInputFlowModel above the *ngFor, as shown in the corresponding end-to-end test.

Q: Why is the usage so complicated?
A: This is a product of multiple iterations and the first one that does not feel like it's totally counteracting Angular's mechanics. If you have any ideas for a better architecture that can provide the same functionality, please share your ideas with an issue or pull request.

Q: Can I use iterables other than arrays?
A: Yes and no, you can pass any iterable into the ngxInputFlow input and it should work, but ngxInputFlow will always emit an array as its output. Also, *ngFor may have problems with some types of iterables.

Q: Is there a TS/JS API that I can use to do some fancy stuff?
A: The package also exports an ArrayManager that you can inject inside of an element with ngxInputFlow on it. It primarily has some methods to perform emptiness checks on parts of the array.

Q: Can I nest multiple ngxInputFlows for my nested array structure?
A: Yes, absolutely! Here's an example of it in action from the corresponding end-to-end test (obviously not styled at all, just like the simple example at the top).

ngx-input-flow nested demo

Just make sure you do not put the outer ngxInputFlowModel on the same element or below the inner ngxInputFlow, otherwise it will attach to the inner one and your outer ngxInputFlow will not be notified of changes.

Package Sidebar

Install

npm i ngx-input-flow

Weekly Downloads

7

Version

1.3.0

License

MIT

Unpacked Size

88.9 kB

Total Files

37

Last publish

Collaborators

  • jeysal