Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering in a table issue: widget is rendered as a div with no structure #10

Open
vindarel opened this issue Mar 2, 2020 · 3 comments

Comments

@vindarel
Copy link
Contributor

vindarel commented Mar 2, 2020

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(&quot;1402%3A031f2f8e626ed376d62fe6024238df39b2eac76d&quot;, $(this), &quot;&quot;); return false;">

      <span>
        <input type="submit" title="Add 1 copy to your stock" value="+&nbsp;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>

Selection_045

  1. tracing my render function: it is called.

  2. logging get-html-tag and thus spinneret:get-html-path: the path is NIL (??)

  3. I tried rendering my widget with an enclosing :tr: it doesn't change that the path is NIL and the rendered html as no td but all the fields as text.


Do you have any pointers or best practices to share?

ps: code

@vindarel
Copy link
Contributor Author

vindarel commented Mar 2, 2020

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))

@vindarel
Copy link
Contributor Author

vindarel commented Mar 3, 2020

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.

@svetlyak40wt
Copy link
Member

Excuse me, can't dive into this problem now.

@svetlyak40wt svetlyak40wt transferred this issue from 40ants/weblocks Jan 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants