Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Example of autocompletion box using Weblocks
;; This example illustrates how to call actions from JS and update the widget in response.
;; It is incomplete but could be refactored into reusable library.
;; Hope, somebody will do this some day.
(defpackage #:weblocks-autocomplete
(:use #:cl))
(in-package weblocks-autocomplete)
(ql:quickload '(weblocks log4cl))
(defparameter *data-to-complete*
"Belo Horizonte"
"Dar es Salaam"
"Ho Chi Minh City"
"Hong Kong"
"Kuala Lumpur"
"Saint Petersburg"
"Washington, D.C."
(weblocks/widget:defwidget completions ()
((visible :initform nil
:reader completions-visible)
(items :initform nil
:reader completions-list)))
(weblocks/widget:defwidget autocomplete-box ()
((action-code :initarg :action-code
:reader action-code)
(completions :initform (make-instance 'completions)
:reader completions)))
(defmethod autocomplete ((widget autocomplete-box) &rest args)
(log:info "Autocompleting" args)
(let* ((completions (completions widget))
(text (getf args :value)))
(setf (slot-value completions 'items)
(remove-if-not (lambda (item)
(str:starts-with-p text item :ignore-case t))
(setf (slot-value completions 'visible)
(weblocks/widget:update completions)))
(defmethod initialize-instance :after ((obj autocomplete-box) &rest args)
(declare (ignorable args))
(setf (slot-value obj 'action-code)
(lambda (&rest args)
(apply #'autocomplete obj args)))))
(defmethod weblocks/widget:render ((box autocomplete-box))
(let ((js-code
(format nil "initiateActionWithArgs(\"~A\", \"\", {\"value\": this.value})"
(action-code box))))
(:input :type "text"
:placeholder "Autocomplete"
:oninput js-code)
(weblocks/widget:render (completions box)))))
(defmethod weblocks/widget:render ((widget completions))
(let ((style (if (completions-visible widget)
(format nil "position:absolute;z-index:1000;background:#F1F1F1;list-style:none;padding:5px;")
(format nil "display:hidden"))))
(:ul :style style
(loop for item in (completions-list widget)
do (:li item))))))
(weblocks/app:defapp test-app
:prefix "/")
(weblocks/widget:defwidget index-page ()
((input :initform (make-instance 'autocomplete-box)
:reader input)))
(defmethod weblocks/widget:render ((widget index-page))
(:p "This is a demo of the autocompletion widget:")
(weblocks/widget:render (input widget))
(:p "A text to check that completion results will float above.")))
(defmethod weblocks/session:init ((app test-app))
(declare (ignorable app))
(make-instance 'index-page))
;; This should be used to add JS and CSS to the widget
;; Examples can be found in the Ultralisp's code:
;; (defmethod weblocks/dependencies:get-dependencies ((box autocomplete-box))
;; (append (call-next-method)
;; (weblocks/dependencies:make-dependency)))

This comment has been minimized.

Copy link
Owner Author

@svetlyak40wt svetlyak40wt commented Sep 24, 2020

Here is a Gif with a demo:

2020-09-24 23 08 21

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment