[Bese-devel] I'm simply not getting it:

Marco Baringer mb at bese.it
Tue Jun 21 14:42:35 UTC 2005


Friedrich Dominicus <frido at q-software-solutions.de> writes:

> (in-package :qss.web.ucw)
>
> ;; end of cut+paste code 
> (defparameter *test-application*
>   (make-instance 'cookie-session-application
>                  :url-prefix "/ucw/test/"
>                  :tal-generator (make-instance 'yaclml:file-system-generator
>                                                :cachep t
>                                                :root-directories (list *ucw-tal-root*))
>                  :www-roots (list (merge-pathnames "./ucw/test/" *ucw-tal-root*))))

this is right (as long as you remeber to register the app when you
startup the server).

> (defcomponent downloader-window (simple-window-component)
>   ((body :component simple-container :accessor example-window.body))
>   (:default-initargs
>       :title "UCW Examples" :stylesheet "stylesheet.css")
>   (:documentation "The main window component for the example application."))
>
> (defmethod render-on ((res response) (app downloader-window))
>   (<:h1 "Downloader Example")
>   (render-on res (example-window.body app)))
>
> (defcomponent simple-address (form-component)
>   ((name :accessor name 
>          :component (text-field))
>    (email :accessor email
>           :component (text-field)))
>   (:default-initargs :title "Downloader " :stylesheet "/css/qss.css"))

this is all right.

> (defaction psav ((adr simple-address))
>   (<:html
>    (<:body
>     "here we are")))
>  ;;   "name = " (lisp-value (name adr))
> ;;    "email = "  (lisp-value  (email adr)))))

this is wrong. you can't emit html in actions. you need to call a
component in an action, the component can then spit out the html:

(defcomponent show-address (simple-window-component)
  ((address :accessor address :initarg :address)))

(defmethod render-on ((res response) (s show-address))
  (<:p "here we are!")
  (<:table
    (<:tr (<:td "Name:") (<:td (<:as-html (lisp-value (name (address s))))))
    (<:tr (<:td "E-Mail:") (<:td (<:as-html (lisp-value (email (address s))))))))

> (defmethod render-on ((res response) (adr simple-address))
>   (<ucw:form :action (psav adr) :method "POST"
>              (<:table
>               (<:tr
>                (<:td "You're name please")
>                (<:td (<ucw:input :type "text"
>                                  :accessor (lisp-value (name adr))
>                                  :size 30)))
>               (<:tr
>                (<:td "you're email: ")
>                (<:td (<ucw:input :type "text"
>                                  :accessor (lisp-value (email adr))
>                                  :size 30)))              
>               (<:tr 
>                (<:td (<:input :type "submit" :value "submit"))
>                (<:td)))))
>
> (defentry-point "index.ucw" (:application *test-application*) ()
>   (call 'downloader-window))
>
> (defmethod shared-initialize :after ((window downloader-window) slot-names &rest initargs)
>   "Initialize the components contained in (example.body APP)."
>   (declare (ignore slot-names initargs))
>   (let ((container (example-window.body window)))
>     (flet ((add-component (type &optional (name type))
> 	     (setf (find-component container name) (make-instance type))))
>       (add-component 'simple-address)
>       (setf (container.current-component-name container)
> 'simple-address))))

this can be simplified to:

(defmethod shared-initialize :after ((window downloader-window) slot-names &rest initargs)
  (declare (ignore slot-names initargs))
  (initialize-container ((example-window.body window))
    (simple-address 'simple-address)))

> Why do I see not output through psav?

because during the execution of actions yaclml:*yaclml-stream* (which
is where <:html, <:body and friends send their output) is bound to T.

> I do not see any error I do not see any output. 



> What I want it simply put:
> - Getting a form with two input text-fields
> - after submitting that form I want to see what has been send

how's this:

(defentry-point "index.ucw" (:application *test-application*) ()
  (call 'show-address :address (call 'get-address)))

(defclass address ()
  ((name :accessor name :initarg :name :initform "")
   (email :accessor email :initarg :email :initform "")))

(defcomponent address-manipulator-mixin ()
  ((address :accessor address :initarg :address :backtrack t
            :initform (make-instance 'address))))

(defcomponent show-address (simple-window-component address-manipulator-mixin)
  ())

(defmethod render-on ((res response) (s show-address))
  (<:p "Your address:")
  (<:table
    (<:tr (<:td "Name:") (<:td (<:as-html (name (address s)))))
    (<:tr (<:td "Email:") (<:td (<:as-html (email (address s)))))))

(defcomponent get-address (simple-window-component address-manipulator-mixin)
  ((message :accessor message :initarg :message :initform nil)))

(defmethod render-on ((res response) (g get-address))
  (<:p "Please submit an address:")
  (when (message g)
    (<:p :style "color: #ff0000; font-weight: bold"
      (<:as-html (message g))))
  (<ucw:form :action (ok g)
    (<:table 
      (<:tr (<:td "Name:") (<:td (<ucw:text :accessor (name g))))
      (<:tr (<:td "Email:") (<:td (<ucw:text :accessor (email g))))
      (<:td (<:td :colspan 2 :align "center"
              (<:input :type "submit"))))))

(defaction ok ((g get-address))
  (if (arnesi:aand (name g)  (string/= "" it)
                   (email g) (string/= "" it))
      (answer (make-instance 'address :name (name g) :email (email g)))
      (setf (message g) "Sorry, you must supply both a name and an email.")))

things worth noting:

1) every different page we want to show has a component.

2) the 'page flow' of the app (the way in which the user moves from
   one page to the next) is entirely contained in the entry-point.

3) i've distinguished between address objects (model in mvc terms) and
   the different ways of rendering address (view in mvc). you don't
   always need to make this split and could just reuse the components
   themselves.

4) macros and functions could be added to make simple examples like
   these even simpler. since real world stuff almost always needs this
   level of complexitly i'm not going to add said macros (but will
   accept patches).

> Do I always need something like the downloader-window component? and
> add some tother components to this window?

no, you don't need it. it all depends on how you want to structure
your app.

hth.

-- 
-Marco
Ring the bells that still can ring.
Forget the perfect offering.
There is a crack in everything.
That's how the light gets in.
	-Leonard Cohen



More information about the bese-devel mailing list