Lars Rune Nøstdal wrote:
Hi Lispers, Ok, starting to get the hang of this, but I'm having a small issue maybe you guys could help me with.
I'm playing with some AJAX-stuff and .. hm .. not sure how to explain this proper, but ..
Fair warning: I have never programmed a Web app, barely done anything with HTML, and understood almost nothing of what you wrote. :) But this (check me: input form field initialized from a database record field, then overwritten by user so data must flow the other way back to the DB?) happens all the time in standalone apps, so...
I have an INPUT-element (HTML) that can be used for both input of data (client-initiated) and output of data (server-initiated), and I'd like to block the observer so it does not react on input from the client and tries to re-update the element ..
..or maybe "blocking" the observer isn't right at all, maybe I'm going about this the wrong way..?
As I said, this comes up all the time, and what you tried is the tempting automatic flow:
DB(existing value -> Input(as initial value) -> DB(new value)
Your code is what I think about writing even after ten years of using Cells. So how do we break the cycle? There are several ways I have handled this.
1. In the slot definition, specify:
(value ...etc... :unchanged-if 'string=)
You will still make the return trip to set the input field unnecessarily, but that will be an NOP because the new value will be seen as unchanged, stopping propagation (including calling observers). The default test is EQL and it is easy in even simple code for 'string= but un-EQL strings to arise and start cycling.
To avoid even the beginnings of a roundtrip, hey, have the observer take a peek at where it is about to write and decide if it needs to. Not as much fun as letting Cells worry about it, but this one observer (I gather) is handling all the HTML input fields, so...?
Now I revert to my earlier disclaimer about being Web-ignorant: I think The Right Answer overall will be decided by the exact nature of the Web stuff, so I will just continue dumping alternatives
2. Does the DB flow to the form only when the form is opened? If so, the HTML input fields can have a something another Cells user just requested: a rule that runs once at initialization time and then becomes a /Cells/ input. ie, the slot starts as c-formula but then becomes c-input. (No dependencies are recorded during the initial rule invocation.) Only the HTML input field has an observer writing back to the corresponding DB field. Now if only cells had some frickin decent doc I could tell you the syntax. Maybe:
(c-formula (:inputp t) <code to lookup value for this field>)
If that is what you settle on and it does not work I will research further.
3. if you are in a multi-user environment or for any other reason need to update the form programmatically at the same time the user is typing, well, things will be pretty exciting for the user <g>, and it may be time to consider the failsafe: do not try to use Cells dataflow where the application really needs to decide the dataflow. An application flow will have to be concocted, hopefully facilitated by Cells, but always keep in mind that the functionality might dictate more savvy than the Cells changed/not-changed propagation smarts.
hth, ken
Here is some code:
(defobserver value ((value-attribute ValueAttribute)) (cells::trc "ValueAttribute changing from" old-value :to new-value) (terpri) ;; Update the value-attribute of the HTML-element on the client-side. (setAttribute (parent-of value-attribute) (name-of value-attribute) "value" (princ-to-string (value-of value-attribute))))
(defmethod onkeyup ((value-attribute ValueAttribute) (parent Container) &rest event-args) (format t "onkeyup: ~A~%" (fifth event-args)) (setf (value-of value-attribute) (first event-args)))
`onkeyup' is called from the client-side and since (setf value-of ..) triggers the observer for the slot `value', it tries to "redraw" what's already on the client-side.