With a little help from you

79 views
Skip to first unread message

Fred

unread,
Oct 20, 2012, 10:51:42 AM10/20/12
to webl...@googlegroups.com
Hello,

i try to write a "search (ldap)" page with weblocks :
- a widget which display a form with an input text field and a submit button
- a second widget which display the results
- a main widget which display the two widgets

i wrote a "data" class and a search function (ldap) stored in src/model/data.lisp
i wrote defview functions too (table and data), but no Form view because i do not need to modify datas.

As far as i understant :
- i need to write a new widget for the "search" one
- i need to use a datagrid widget to display results
- i need a composite widget to the main page

For the new widget (search), can i use an existing one (with inheritance) ?
Or must i write my own widget with some render functions (like render-input-field) in a render-widget-body method ?
I looked at simpleform, quickform, login, but i steel do not see how to start.

With a little help from you, i could follow the right way.

Thanks.

Regards.





Олексій Замковий

unread,
Oct 20, 2012, 1:02:36 PM10/20/12
to webl...@googlegroups.com


2012/10/20 Fred <iri...@gmail.com>
Hi, I've used quickform for this and now have own filtering widget https://github.com/html/weblocks-filtering-widget
It must satisfy your needs.
 

With a little help from you, i could follow the right way.

Thanks.

Regards.





--
You received this message because you are subscribed to the Google Groups "weblocks" group.
To view this discussion on the web visit https://groups.google.com/d/msg/weblocks/-/eXCSRaVpiocJ.
To post to this group, send email to webl...@googlegroups.com.
To unsubscribe from this group, send email to weblocks+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/weblocks?hl=en.

Nandan Bagchee

unread,
Oct 21, 2012, 2:49:53 AM10/21/12
to webl...@googlegroups.com


> i try to write a "search (ldap)" page with weblocks :
> - a widget which display a form with an input text field and a submit button
> - a second widget which display the results
> - a main widget which display the two widgets

The main widget is your composite widget.

>
> i wrote a "data" class and a search function (ldap) stored in src/model/data.lisp
> i wrote defview functions too (table and data), but no Form view because i do not need to modify datas.

Standard scaffold form view should be enough unless you need complex validations.

>
> As far as i understant :
> - i need to write a new widget for the "search" one
> - i need to use a datagrid widget to display results
> - i need a composite widget to the main page

Not all of this is required.

Call the data search function from the form submit function. Capture results of search and assign grid widget data to it. Mark grid widget dirty.

Once you get this working we can work on a cleaner approach, eg maybe just mark parent dirty.

>
> For the new widget (search), can i use an existing one (with inheritance) ?
> Or must i write my own widget with some render functions (like render-input-field) in a render-widget-body method ?
> I looked at simpleform, quickform, login, but i steel do not see how to start.
>
> With a little help from you, i could follow the right way.
>
> Thanks.
>
> Regards.
>

Post code or a github gist for better guidance.

Fred

unread,
Nov 1, 2012, 11:20:57 AM11/1/12
to webl...@googlegroups.com
Hello,

finally i wrote what i want : a simple ldap search page.

i used the login widget as a model.

My main widget is a composite widget of :
 - 1 ldap-search widget
 - 1 datalist widget

One point not obvious for me : when i get data from ldap server, how can i pass them to the datalist widget ?
I used a memory store to do this. Is it the right way ?

There is some fog between me and weblocks :)
This first success is like a light in the dark :)

No more words, the code

Project Name : info-utilisateur

##########################
# File conf/store.lisp
##########################
(in-package :info-utilisateur)

(defstore *ldap-results-store* :memory)

##########################
# File src/init-session.lisp
##########################
 (in-package :info-utilisateur)

;; Define callback function to initialize new sessions
(defun init-user-session (root)
  (clean-ldap-results-store)
  (setf (composite-widgets root)
        (make-main-page)))

##########################
# File src/layout.lisp
##########################
(in-package :info-utilisateur)

(defun make-main-page ()
 (make-instance 'composite :widgets
(list
 (make-instance 'ldap-search-widget)
 (make-instance 'datalist
:name 'ldap-people
                                 :data-class 'ldap-people
                                 :item-data-view 'ldap-people-data-view))))

##########################
# File src/model/people.lisp
##########################

(in-package :info-utilisateur)

(defclass ldap-people ()
  ((id :accessor ldap-people-id)
   (name :accessor ldap-people-name
 :initarg :name
 :type string)
   (email :accessor ldap-people-email
   :initarg :email
   :type string)))

;;; Data View
(defview ldap-people-data-view (:type data :inherit-from '(:scaffold ldap-people))
  (id :hidep t)
  (name :label "Identité"))

##########################
# File src/widget/ldap-search.lisp
##########################
(in-package :info-utilisateur)

(defview ldap-search-view (:type form :persistp nil
                             :buttons '((:submit . "Rechercher"))
                             :caption "Rechercher dans l'annuaire"
                             :focusp t)
  (name :requiredp t :required-indicator nil :label "Nom ou prénom"))

(defun clean-ldap-results-store ()
  (dolist
      (obj (find-persistent-objects *ldap-results-store* 'ldap-people))
    (delete-persistent-object *ldap-results-store* obj)))
 

(defwidget ldap-search-widget ()
  ((view :accessor ldap-s-view
         :initform 'ldap-search-view
         :initarg :view)
   (quickform :accessor ldap-quickform
     :initform nil
     :initarg :quickform)))))

(defmethod render-widget-body ((obj ldap-search-widget) &rest args)
  (declare (ignore args))
   (render-widget (ldap-quickform obj)))

(defmethod initialize-instance :after ((obj ldap-search-widget) &rest initargs &key &allow-other-keys)
  (declare (ignore initargs))
  (setf (ldap-quickform obj)
        (make-quickform (ldap-s-view obj)
                        :on-success (lambda (w o)
     (declare (ignore w))
     (clean-ldap-results-store)
     (search-people (slot-value o 'name))
     (mark-dirty (widget-parent obj))
                                      (answer obj)))))
(defun search-people (byname)
  (let ((ldap-conn (ldap:new-ldap :host *ldap-server*
                                  :base *ldap-base*)))
    (when (ldap:bind ldap-conn)
      (let (
            (filter (concatenate 'string
                                 "(&(objectClass=person)(displayName=*"
                                 byname
                                 "*))")))
        (ldap:dosearch (usr (ldap:search ldap-conn filter))
 (persist-object *ldap-results-store*
 (make-instance 'ldap-people
:name (car (ldap:attr-value usr :displayname))
:email (car (ldap:attr-value usr :mail)))))))))


Advices are welcome.

Fred

unread,
Nov 9, 2012, 10:24:14 AM11/9/12
to webl...@googlegroups.com
Hello,

in my previous code, i store ldap results into a memory store,
but stores are shared between widgets, isn't it ?

So on different request from different web browser,
the same store is used and the data are overwritten.

How do i store the data from the search widget ?
In a slot of the widget ? But how can i inform the datalist widget about this data ?

Thanks

Regards.


Willem Rein Oudshoorn

unread,
Nov 9, 2012, 10:51:13 AM11/9/12
to webl...@googlegroups.com
Fred <iri...@gmail.com> writes:

> Hello,
>
> in my previous code, i store ldap results into a memory store,
> but stores are shared between widgets, isn't it ?

I am not sure exactly what previous code you are refering to, but
I don't think it matters.
>
> So on different request from different web browser,
> the same store is used and the data are overwritten.
>
> How do i store the data from the search widget ?
> In a slot of the widget ? But how can i inform the datalist widget about
> this data ?

One way of doing this is to write your own store. This might sound
scarier than it really is. For example write a class called:

search-key-and-results

which implements the store interface.
Almost all methods of the store interface can be no-ops.
The only two that are really important for displaying are:

(defmethod find-persistent-objects ((store hash-store) class-name
&key order-by range &allow-other-keys)

(defmethod count-persistent-objects ((store hash-store) class-name &key &allow-other-keys)
(hash-table-count (data store)))


Also add to the search-key-and-results class an ivar 'search-string'.

If build your class search-key-and-results in such a way, you can
do roughly the following:

...
(let ((search-and-results (make-instance 'search-key-and-result)))
...
(make-instance 'quickform :data search-and-results .....)
(make-instance 'datalist :class-store search-and-results))

....

Now your datalist can access your search results using the store
interface.

The quickform will render your search box, using the normal mechanisms,
so you can modify the 'search-string' slot.

One thing that will not work out of the box is that you have to call
mark-dirty on your datalist widget after the content of your
search results is changed.

Kind regards,
Wim Oudshoorn.

Fred

unread,
Nov 15, 2012, 4:01:14 AM11/15/12
to webl...@googlegroups.com, woud...@xs4all.nl
Hello,

thanks for your help.

class-store slot is the answer i'm looking for.

I do not need to create my own store,
instead i use memory store :
(make-instance 'weblocks-memory:memory-store)

A let to create this new store within each new session
and to use it with my "search widget" and the quickform.

Please watch the code here below :

(defwidget ldap-search-widget ()
  ((view :accessor ldap-s-view
         :initform 'ldap-search-view
         :initarg :view
         :documentation "A form view for an LDAP search")
   (search-store :accessor search-store
:initform nil
:initarg :search-store)
   (quickform :accessor ldap-quickform
     :initform nil
     :initarg :quickform)))

(defun make-main-page () 
  (let ((search-and-results (make-instance 'weblocks-memory:memory-store)))
    (make-instance 'composite :widgets
  (list
   (make-instance 'ldap-search-widget 
  :search-store search-and-results)

   (make-instance 'datalist
  :name 'ldap-people
  :class-store search-and-results
  :data-class 'ldap-people
  :item-data-view 'ldap-people-data-view)


(defmethod initialize-instance :after ((obj ldap-search-widget) 
      &rest initargs 
      &key &allow-other-keys)
  (declare (ignore initargs))
  (setf (ldap-quickform obj)
        (make-quickform (ldap-s-view obj)
:class-store (search-store obj)
                        :on-success (lambda (w o)
     (declare (ignore w))
     (clean-ldap-results-store 
      (search-store obj))
     (search-people (slot-value o 'name) 
    (search-store obj))
     (mark-dirty (widget-parent obj))
                                      (answer obj)))) )


Every new search (on-success lambda), 
get results and mark dirty 
the parent widget, but is this lambda the right place
to use mark-dirty ?

Thanks.

Best Regards.
--
Fred


Willem Rein Oudshoorn

unread,
Nov 15, 2012, 3:27:54 PM11/15/12
to webl...@googlegroups.com
Fred <iri...@gmail.com> writes:

> Hello,
>
> thanks for your help.
>
> class-store slot is the answer i'm looking for.
>
> I do not need to create my own store,
> instead i use memory store :
> (make-instance 'weblocks-memory:memory-store)

Ah, yes that should work to.
In my opinion, yes, the lambda is the right place.
The only thing I would consider changing is the target of the
mark-dirty. You could give the ldap-search-widget
an ivar, result-widget and store in that ivar your datalist
widget. In that case in the lambda you
can write (mark-dirty (result-widget obj)).

However, your way or what I suggest above, are so similar that
it does not really matter. The only slight advantage I can
see with what I propose is that you do not have to put the
ldap-search-widget together with the datalist widget
in one parent widget. It will give you the freedom
to put the results in a complete different place in the widget tree.

Kind regards,
Wim Oudshoorn.

Fred

unread,
Nov 18, 2012, 11:30:02 AM11/18/12
to webl...@googlegroups.com, woud...@xs4all.nl

Le jeudi 15 novembre 2012 21:28:05 UTC+1, Willem Rein Oudshoorn a écrit :

In my opinion, yes, the lambda is the right place.
The only thing I would consider changing is the target of the
mark-dirty.   You could give the ldap-search-widget
an ivar, result-widget and store in that ivar your datalist
widget.   In that case in the lambda you
can write (mark-dirty (result-widget obj)).  

However, your way or what I suggest above, are so similar that
it does not really matter.   The only slight advantage I can
see with what I propose is that you do not have to put the
ldap-search-widget together with the datalist widget
in one parent widget.   It will give you the freedom
to put the results in a complete different place in the widget tree.

Kind regards,
Wim Oudshoorn.


Thanks for you help.
i did what you suggested, 
i'm agree with your analysis. 


Best regards,
Fred.
Reply all
Reply to author
Forward
0 new messages