Rendering in a table issue: widget is rendered as a div with no structure
Hi,
I have an issue rendering a widget as a row inside a table. It is rendered inside a div and it doesn't respect the markup of my render function.
This reminds me of a fix we implemented some months ago. We corrected get-html-tag for it to consult Spinneret and return a :tr or a :td if we are inside a table, and a :div otherwise.
I start like this:
(defmethod render ((widget book-widget))
(let ((book (book widget)))
(with-html
(:td (bookshops.models:title book))
(:td (bookshops.models:authors book))
(:td (bookshops.models:price book) "€")
(:td (format nil "x ~a" (bookshops.models:quantity book)))
(:td (with-html-form (:POST (lambda (&key &allow-other-keys)
(add-book widget)))
(:input :type "submit"
:title "Add 1 copy to your stock"
:value "+ 1"))))))
add-book updates the widget:
(defun add-book (book-widget)
"Add one copy to the default place."
(let ((book (book book-widget)))
(bookshops.models:add-to *place*
book)
(update book-widget)))
I render the table inside my main widget:
(:table
(:tbody
(loop for elt in (books widget)
do (with-html
(:tr (render elt))))))))
and it displays the table correctly. When I click on the +1 button, a new widget is inserted above the widget that was clicked, inside the tr, it is rendered as a div and it doesn't contain any :td, only the plain text title + author + price + quantity concatenated.
<tr> <-- tr of first page load
// the thing appearing after the click:
<div class="widget book-widget" id="dom54">Le langage lisp
// everything is inlined, rendered as text, no td:
Cayrol
13.72 €€
x 7
<form action="/" method="post" onsubmit="initiateFormAction("1402%3A031f2f8e626ed376d62fe6024238df39b2eac76d", $(this), ""); return false;">
<span>
<input type="submit" title="Add 1 copy to your stock" value="+ 1">
<input name="action" type="hidden" value="1402:031f2f8e626ed376d62fe6024238df39b2eac76d"></span>
</form>
</div>
// the widget that was clicked:
<td>Le langage lisp </td>
<td>Cayrol</td>

-
tracing my render function: it is called.
-
logging
get-html-tagand thusspinneret:get-html-path: the path is NIL (??) -
I tried rendering my widget with an enclosing
:tr: it doesn't change that the path is NIL and the rendered html as notdbut all the fields as text.
Do you have any pointers or best practices to share?
ps: code
Reproducible example:
(defpackage testtable
(:use #:cl
#:weblocks-ui/form
#:weblocks/html)
(:import-from #:weblocks/widget
#:render
#:update
#:defwidget)
(:import-from #:weblocks/actions
#:make-js-action)
(:import-from #:weblocks/app
#:defapp)
(:import-from #:weblocks-navigation-widget
#:defroutes))
(in-package :testtable)
(defapp testtable :prefix "/")
(weblocks/debug:on)
(defparameter *quantity* 0 "Simulate a book's quantity in the DB.")
(defwidget book-widget (weblocks-ui:ui-widget)
())
(defun add-book (book-widget)
"Add one copy to the default place."
(incf *quantity*)
(update book-widget))
(defmethod render ((widget book-widget))
(with-html
(:td "Title: On Lisp")
(:td "quantity:" *quantity*)
(:td (with-html-form (:POST (lambda (&key &allow-other-keys)
(add-book widget)))
(:input :type "submit"
:value "Add 1")))))
(defwidget book-list-widget ()
())
(defmethod render ((widget book-list-widget))
(with-html
(:table
(:tbody
(dolist (elt (list (make-instance 'book-widget)
(make-instance 'book-widget)))
do (with-html
(:tr (render elt))))))))
(defmethod weblocks/session:init ((app testtable))
(declare (ignorable app))
(make-instance 'book-list-widget))
(defun start ()
(weblocks/server:start :port 8910))
idea: the tbody.
(defmethod get-html-tag ((widget t))
(let ((path (get-html-path)))
(log:debug path)
(case (first path)
(:table
:tr)
(:tr
:td)
(t
:div))))
but (get-html-path) still returns NIL, hence get-html-tag a DIV.
Excuse me, can't dive into this problem now.