Hi,
This was mentioned a while ago and is causing a problem now. When an ajax request comes in, one of the things that gets updated is the input value. For example...
old: <input name="term" value=""/>
...user types in "progv" and hits TAB
new: <input name="term" value="progv"/>
We want the model on the server to update itself to reflect this change but we don't need to send it down to the browser because the browser already knows. The problem this is causing (and this is something we'll need to take a mental note of for the future) is that the event binding for the input element is lost when that element is replaced. That means any actions after the first don't trigger an ajax request.
We could rebind the event on the new element but I think its better not to send it in the first place.
I think this would apply to all UI elements so if that's the case, the solution is probably to filter updates containing these elements the same way that ascendant and redundant nodes get filtered in the code below.
(let ((updt (loop for (h . xh) in (updates self) unless (loop for (h2 . nil) in (updates self) thereis (unless (eq h h2) (when (fm-ascendant-p h2 h) (trc nil "suppressing redundant" h :seeing-ascendant h2 (id h2)) t))) collect xh)))
I've pushed a new version out to the repo but haven't dealt with this problem yet.
Another thing you might notice if you look at commented out code in the example is that the radio button at the bottom seems a bit verbose. Radiobuttons could probably do with a layer on top providing a nicer way of creating them. At the moment, user code has to create labels, manage the checked/unchecked status, and the value for each input. It should provide something like celtk's mk-radio
-- Andy
Andy Chambers wrote:
Hi,
This was mentioned a while ago and is causing a problem now. When an ajax request comes in, one of the things that gets updated is the input value. For example...
old: <input name="term" value=""/>
...user types in "progv" and hits TAB
new: <input name="term" value="progv"/>
We want the model on the server to update itself to reflect this change but we don't need to send it down to the browser because the browser already knows. The problem this is causing (and this is something we'll need to take a mental note of for the future) is that the event binding for the input element is lost when that element is replaced. That means any actions after the first don't trigger an ajax request.
We could rebind the event on the new element but I think its better not to send it in the first place.
I think this would apply to all UI elements so if that's the case, the solution is probably to filter updates containing these elements the same way that ascendant and redundant nodes get filtered in the code below.
(let ((updt (loop for (h . xh) in (updates self) unless (loop for (h2 . nil) in (updates self) thereis (unless (eq h h2) (when (fm-ascendant-p h2 h) (trc nil "suppressing redundant" h :seeing-ascendant h2 (id h2)) t))) collect xh)))
I've pushed a new version out to the repo but haven't dealt with this problem yet.
Lessee. The update happens in the observer on the xhtml slot, which is passed the clos instance for the node along with the old and new values, inter alia.
(defobserver xhtml ((self html)) (when new-value (trc nil "new xhtml for" self) (assert (u^ web-app)) (push (cons self (format nil "$("#~a").html("~a")" (^id) (js-escape new-value))) (updates (u^ web-app)))))
I suggest you have an option or options on the clos node that controls whether the update gets sent:
(mk-input (:name "s" :id "s" :-type "text" :send :once ;; default t (other constraints possible, ;; including a closure over other variables ;; that returns t to send, nil not :any-more-info 'needed-t-control :value (c? (term (u^ web-apropos)))))
And then:
(defobserver xhtml ((self html)) (when (and new-value (do-send self new-value old-vale)) (trc nil "new xhtml for" self) (assert (u^ web-app)) (push (cons self (format nil "$("#~a").html("~a")" (^id) (js-escape new-value))) (updates (u^ web-app)))))
And:
(defmethod do-send (self new-value old-value) (bwhen (s (send self)) (case s ((t) t) ; parens needed, long story (:once (not old-value)) (otherwise ; better be a function :) (funcall s self new-value old-value)))))
Note I made it a method so one could just do:
(defmethod ((self input) new old) (not old))
That might be too extreme -- perhaps we /do/ sometimes need to get an input field out there again, perhaps with a different binding, or even to do symbol-completion (weird in apropos, but just as an example) -- but the flexibility might help someday. Maybe start with a defun and see if a GF is ever needed.
Another thing you might notice if you look at commented out code in the example is that the radio button at the bottom seems a bit verbose. Radiobuttons could probably do with a layer on top providing a nicer way of creating them. At the moment, user code has to create labels, manage the checked/unchecked status, and the value for each input. It should provide something like celtk's mk-radio
I'll look at this next.
kt
Ken Tilton wrote:
Andy Chambers wrote:
Hi,
This was mentioned a while ago and is causing a problem now. When an ajax request comes in, one of the things that gets updated is the input value. For example...
old: <input name="term" value=""/>
...user types in "progv" and hits TAB
new: <input name="term" value="progv"/>
We want the model on the server to update itself to reflect this change but we don't need to send it down to the browser because the browser already knows. The problem this is causing (and this is something we'll need to take a mental note of for the future) is that the event binding for the input element is lost when that element is replaced. That means any actions after the first don't trigger an ajax request.
We could rebind the event on the new element but I think its better not to send it in the first place.
I think this would apply to all UI elements so if that's the case, the solution is probably to filter updates containing these elements the same way that ascendant and redundant nodes get filtered in the code below.
(let ((updt (loop for (h . xh) in (updates self) unless (loop for (h2 . nil) in (updates self) thereis (unless (eq h h2) (when (fm-ascendant-p h2 h) (trc nil "suppressing
redundant" h :seeing-ascendant h2 (id h2)) t))) collect xh)))
I've pushed a new version out to the repo but haven't dealt with this problem yet.
Lessee. The update happens in the observer on the xhtml slot, which is passed the clos instance for the node along with the old and new values, inter alia.
(defobserver xhtml ((self html)) (when new-value (trc nil "new xhtml for" self) (assert (u^ web-app)) (push (cons self (format nil "$("#~a").html("~a")" (^id) (js-escape new-value))) (updates (u^ web-app)))))
I suggest you have an option or options on the clos node that controls whether the update gets sent:
(mk-input (:name "s" :id "s" :-type "text" :send :once ;; default t (other constraints possible, ;; including a closure over other variables ;; that returns t to send, nil not :any-more-info 'needed-t-control :value (c? (term (u^ web-apropos)))))
And then:
(defobserver xhtml ((self html)) (when (and new-value (do-send self new-value old-vale)) (trc nil "new xhtml for" self) (assert (u^ web-app)) (push (cons self (format nil "$("#~a").html("~a")" (^id) (js-escape new-value))) (updates (u^ web-app)))))
And:
(defmethod do-send (self new-value old-value) (bwhen (s (send self)) (case s ((t) t) ; parens needed, long story (:once (not old-value)) (otherwise ; better be a function :) (funcall s self new-value old-value)))))
Note I made it a method so one could just do:
(defmethod ((self input) new old) (not old))
That might be too extreme -- perhaps we /do/ sometimes need to get an input field out there again, perhaps with a different binding, or even to do symbol-completion (weird in apropos, but just as an example) -- but the flexibility might help someday. Maybe start with a defun and see if a GF is ever needed.
Hmmm, I just realized you are making a library that should be long on ease of use. Perhaps you /do/ want to have the user specifying a minimum as the default, in which case you might well want to special do-send on the input field, also have a 'send' parameter default to :once for input, t for most other things, and then have it all Just Work with fancy black belt behavior available by actually coding values for the :send option including closures, or subclassing input if they have lots of inputs that will have the same odd behavior.
kt
Andy Chambers wrote:
Hi,
This was mentioned a while ago and is causing a problem now. When an ajax request comes in, one of the things that gets updated is the input value. For example...
old: <input name="term" value=""/>
...user types in "progv" and hits TAB
new: <input name="term" value="progv"/>
We want the model on the server to update itself to reflect this change but we don't need to send it down to the browser because the browser already knows. The problem this is causing (and this is something we'll need to take a mental note of for the future) is that the event binding for the input element is lost when that element is replaced. That means any actions after the first don't trigger an ajax request.
We could rebind the event on the new element but I think its better not to send it in the first place.
I think this would apply to all UI elements so if that's the case, the solution is probably to filter updates containing these elements the same way that ascendant and redundant nodes get filtered in the code below.
(let ((updt (loop for (h . xh) in (updates self) unless (loop for (h2 . nil) in (updates self) thereis (unless (eq h h2) (when (fm-ascendant-p h2 h) (trc nil "suppressing redundant" h :seeing-ascendant h2 (id h2)) t))) collect xh)))
I've pushed a new version out to the repo but haven't dealt with this problem yet.
Another thing you might notice if you look at commented out code in the example is that the radio button at the bottom seems a bit verbose. Radiobuttons could probably do with a layer on top providing a nicer way of creating them.
Here is what I did for the exported-only checkbox (untested):
(defmacro mk-checkbox (label attribute &key top-args label-args input-args) `(mk-div (,@topargs) (mk-label (,@label-args :for ,(symbol-name attribute)) ,label) (mk-input (,@input-args :name ,(symbol-name attribute) :id ,(symbol-name attribute) :-type "checkbox" :checked (c? (,attribute (u^ page))) ; parameterize? :value (c? (,attribute (u^ page)))))))
And then you can just do:
(mk-checkbox "Exported Only" exported-only-p :top-args (:one 1 :two 2))
And to think they banned even a preprocessor from Java. :)
Notes: 0. I mentioned first the idea of having a 'watched-parameter' slot on the checkbox. Above macrology lets me achieve even more succinctness without complicating the checkbox implementation which stays as minimal as possible. Who does not get macros?!!! :)
1. Observe that parameters for any node must be in their own list.
2. I added a common parent (an extra mk-div) but hopefully that is OK, seemes right anyway. If not, I have a work-around in mind, but macros only emit one form so it would take (probably) a "flatten" call ... hmmm, I suspect I am being daft: do these things end up going thru a the-kids form anyway, which would flatten any list so the outer mk-div could just be (list...)? Probably.
3. Will the top always be a page? Perhaps that is another parameter.
4. I started with an initial-value parameter then realized that is being set at the page level. Then I noticed both checked and value mirroring that. What I believe I have done (check Celtk) is have an intial-value slot whose observer sets the parameter of whatever node is being controlled (here the page). Actions on the checkbox likewise set the parameter of the controlled node. Then the checkbox value (as you have it) watches the parameter, but we at least author the parameter completely (including initialization) from the authoring of the checkbox. But I can see it going the other way, with the checkbox being, say, an optional interface to a page value that would possibly be maintained/originate elsewhere. Anyway, I am still curious about the checkbox/value redundancy.
kt