cl-forms icon indicating copy to clipboard operation
cl-forms copied to clipboard

feature request: spinneret

Open jgarte opened this issue 3 years ago • 6 comments

Hi could this library support spinneret?

If so, what would be required?

jgarte avatar Mar 15 '22 03:03 jgarte

Hi. Would require a Spinneret renderer.

The equivalent of this file: https://github.com/mmontone/cl-forms/blob/master/src/renderer/who.lisp, but using Spinneret instead of cl-who.

mmontone avatar Mar 15 '22 14:03 mmontone

I think you may be able to mix both cl-who and spinneret,though. If both libraries write to the same output stream..

mmontone avatar Mar 15 '22 14:03 mmontone

I have an example of using cl-who renderer and spinneret at the same time:

(forms:defform my-form ()
	 ((input :string)))

(let ((form (forms:get-form 'my-form)))
	 (with-output-to-string (*html*) 
	   (spinneret:with-html
	     (let ((cl-forms.who:*html* *html*)
		   (spinneret:*html* *html*))
	       (:h1 "This is my form")
	       (forms:with-form-renderer :who
		 (forms:render-form form))
	       (:ul
		(loop for i from 1 to 10
		      do (:li (princ-to-string i))))))))

There may be a cleaner way of connecting things. Feels like a macro should be implemented there .. But this works. cl-who html stream, cl-forms.who:*html* and spinneret:*html* are all bound to the same output stream.

mmontone avatar Mar 15 '22 14:03 mmontone

a problem i encountered with the above approach is that it doesn't work with spinneret:with-html-string, as that macro binds its own, new (i think) spinneret:*html*.


(with-output-to-string (*html*)
  (let ((forms.who:*html* *html*)
        (spinneret:*html* *html*))
    (spinneret:with-html-string
      (:title "new agent")
      (:br))))

returns "".

and the problem with that is that with-html-string can be used by intermediate functions/macros, like pages/grids.

not sure if there is any way to get around this? i tried binding everything to spinneret:*html* as the stream but it also didn't work.

mooseyboots avatar Mar 01 '25 09:03 mooseyboots

i find myself with a little frankenstein html when combining cl-forms and spinneret.

basic example, based on the above method to combine them:

(forms:defform create-agent (:action "/create")
  ((name :string :value "")
   (age :string :value "")
   (location :string :value "")
   (submit :submit :label "Submit")))

 (let ((form (forms::find-form 'create-agent)))
    (with-output-to-string (*html*)
      (let ((forms.who:*html* *html*)
            (spinneret:*html* *html*))
        (spinneret:with-html
          (:doctype)
          (:html
           (:body
             (:h1 "new agent")
             (:main
              (forms:with-form-renderer :who
                (forms:render-form form)))))))))

output (with junk &lt;/form&gt after </form>):

<!DOCTYPE html>
<html lang=en>
 <body>
  <h1>new agent</h1>
  <main><form id='G4521' action='/agents' method='POST'><div><label>Name</label><input type=\"text\" name=\"name\" value=\"\"></input></div><div><label>Age</label><input type=\"text\" name=\"age\" value=\"\"></input></div><div><label>Location</label><input type=\"text\" name=\"location\" value=\"\"></input></div><div><input type='submit' value='Submit' /></div></form>
   &lt;/form&gt;
  </main>
 </body>
</html>

it's possible to unescape the last form by wrapping the call to forms:render-form in spinneret's :raw, but then there are two closing form tags in the html.

mooseyboots avatar Mar 01 '25 10:03 mooseyboots

Not ideal, but you can return NIL to prevent Spinneret from rendering that last form tag:

(let ((form (forms::find-form 'create-agent)))
    (with-output-to-string (*html*)
      (let ((forms.who:*html* *html*)
            (spinneret:*html* *html*))
        (spinneret:with-html
          (:doctype)
          (:html
           (:body
             (:h1 "new agent")
             (:main
              (forms:with-form-renderer :who
                (forms:render-form form)
                nil))))))))

mmontone avatar Mar 01 '25 13:03 mmontone