Creating Custom Components: Credit Card Box
Hawk Chen, Manager, Potix Corporation
Oct. 18, 2024
ZK 9 or later
Overview
In this article, I will guide you on how to create a custom ZK component by combining existing ZK components. Moreover, we'll apply a customized ZK JavaScript widget to enhance client-side behavior.
We will start by demonstrating the process with a single ZK Textbox and then enhance it with a more advanced solution using multiple Textboxes. The smart credit card input field will be customized to accept only numeric entries and will also group the digits into four-digit sets, making it easier to read and verify.
Build with one Textbox
The most straightforward approach is to use a single Textbox for the credit card input and set its `maxlength` and `col` to 16.
<textbox type="tel" cols="16" maxlength="16"/>
However, the downside is that all the numbers appear "crowded together," which makes them difficult to read.
Customize a Number Padding Box
To improve readability, we can customize the textbox widget to insert a space character after every four digits. This customization will also ensure that only numbers are entered.
Here's where you would insert the required widget code in TypeScript:
@zk.WrapClass('business.input.NumberPaddingBox')
// @ts-ignore
class NumberPaddingBox extends zul.inp.Textbox {
/** default onInput event listener **/
doInput_(event: zk.Event) {
super.doInput_(event);
this.removeNonNumericCharacters();
this.addPaddingEach4Digits();
}
removeNonNumericCharacters() {
// @ts-ignore
this.getInputNode().value = this.getInputNode().value.replace(/\D/g, '');
}
addPaddingEach4Digits() {
// @ts-ignore
let value = this.getInputNode().value;
// avoid exceeding credit card number length when pasting texts
value = value.substring(0, 16);
// @ts-ignore
this.getInputNode().value = value.replace(/(\d{4})(?=\d)/g, '$1 ');
}
getZclass() {
return 'z-textbox';
}
}
To apply this customized JavaScript widget to a textbox:
<textbox type="tel" cols="19" maxlength="19" w:use="business.input.NumberPaddingBox"/>
Declare as ZK Component
For ease of use, it's beneficial to declare this setup as a ZK component. This way, developers can use it like a regular component without specifying a custom widget name. Additionally, you can set default attributes for the credit card input.
An example declaration in lang-addon.xml
:
<language-addon>
<addon-name>business-input</addon-name>
<depends>zul</depends>
<language-name>xul/html</language-name>
<version>
<zk-version>10.0.0</zk-version>
</version>
...
<component>
<component-name>creditcardbox</component-name>
<extends>textbox</extends>
<widget-class>business.input.NumberPaddingBox</widget-class>
<property>
<property-name>type</property-name>
<property-value>tel</property-value>
</property>
<property>
<property-name>cols</property-name>
<property-value>19</property-value>
</property>
<property>
<property-name>maxlength</property-name>
<property-value>19</property-value>
</property>
</component>
Check lang-addon.xml specification.
Build with Four Textboxes
If you prefer a more structured input, you can use four separate textboxes to divide the 16 digits, ensuring easier entry and organization.
<zk xmlns:w="client" xmlns:ca="client/attribute">
<textbox type="tel" ca:inputmode="numeric" cols="4" maxlength="4" forEach="1,2,3,4"/>
</zk>
Combine the entries in 4 Textboxes with a Macro
Typically, when using four separate textboxes for credit card input, you would need to retrieve and combine the entries from each box. To simplify this process, you can create a macro component that automatically consolidates the inputs into a single value.
Retrieving the credit card number can then be done using:
getNumber()
Here's where to insert the Java code for the macro component:
public class Creditcardbox4 extends HtmlMacroComponent {
public static final String CSS_CLASS = "z-creditcardbox4";
public Creditcardbox4() {
this.setMacroURI("~./js/business/input/zul/creditcardbox4.zul");
this.setZclass(CSS_CLASS);
}
@Wire("textbox")
protected List<Textbox> textboxList;
/**
* @return credit card number
*/
public String getNumber(){
String number = "";
for (Textbox textbox : textboxList) {
number += textbox.getValue();
}
return number;
}
}
Customize a Focus Jumping Box
Manually moving the focus among four textboxes while entering digits can be cumbersome. To enhance usability, I developed a JavaScript widget with the following features:
- Automatically shifts focus to the next textbox when typing reaches the maximum length.
- Moves focus to the previous textbox when pressing backspace in an empty textbox.
@zk.WrapClass('business.input.FocusJumpingBox')
// @ts-ignore
class FocusJumpingBox extends zul.inp.Textbox {
/** default onInput event listener **/
doInput_(event: zk.Event) {
super.doInput_(event);
this.removeNonNumericCharacters();
this.focusNextBoxIfComplete();
}
...
focusNextBoxIfComplete() {
// @ts-ignore
if (this.getInputNode().value.length == this.getMaxlength()
&& !this.isLastBox()) {
this.nextSibling?.focus();
}
}
/** default onKeyDown event listener **/
doKeyDown_(event: zk.Event) {
super.doKeyDown_(event);
this.focusPreviousBoxOnBackspace(event);
}
focusPreviousBoxOnBackspace(event: zk.Event) {
// @ts-ignore
if (this.getInputNode().value.length == 0
&& !this.isFirstBox()
&& event.key == 'Backspace') {
this.previousSibling?.focus();
}
}
isLastBox() {
return this.nextSibling == null;
}
isFirstBox() {
return this.previousSibling == null;
}
getZclass() {
return 'z-textbox';
}
}
Declare as ZK Component
Due to the component's Java and JavaScript portions, declaring it as a ZK component is advisable for ease of use.
Refer to the following example in lang-addon.xml
:
<language-addon>
<addon-name>business-input</addon-name>
<depends>zul</depends>
<language-name>xul/html</language-name>
<version>
<zk-version>10.0.0</zk-version>
</version>
<component>
<component-name>creditcardbox4</component-name>
<component-class>org.zkoss.business.Creditcardbox4</component-class>
</component>
Try it In Your Project
Using ZK's custom component mechanism, you can create a tailored CreditCardBox component with unique server and client features to enhance the user experience. I hope this has demonstrated how you can customize and extend existing ZK components to meet your needs.
Note that while the methods and ideas mentioned in this article apply to both ZK 9 and ZK 10, the resulting component supports only ZK 10 and later. To try out the Beta version of the component, include the latest version in your Maven pom file from zk repository.
<dependency>
<groupId>org.zkoss.addon</groupId>
<artifactId>business-input</artifactId>
<version>${version}</version>
</dependency>
Then use it in a zul like:
<creditcardbox/>
<creditcardbox4/>
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |