Friday, June 18, 2010

Symfony Form widgets for many-to-many relationship: a new widget implementation - part II

Following part I, here is the final step to code a new symfony form widget in order to improve a many-to-many relationship. After discussing the best UI possible for a many-to-many relationship, we are now going to look how to code it as a symfony widget. I would not pretend it is the best solution, but I believe it is clean enough to be used and it definitively works!

One of the comment point me to the following approach: http://www.ryancramer.com/journal/entries/select_multiple/. It is also an elegant way to do it, unfortunately it does not work for me since my list of available object is extremely long, therefore a select is again not a good approach. Don't get me wrong, my approach is not necessarily the best but it fits a specific user case.

Before starting you can have a look at a demo of what we will get at the end. Here is a video to show the different interactions.

Pre-requisite:

  • symfony 1.3/1.4
  • jQuery 1.4+ and jQuery UI 1.8+. This might seems overkilling for a simple widget but most of the time you are using these 2 libraries in your project already. In jQuery UI you specifically need for this widget the new autocomplete widget.

Ok, no more talk, let's go to the code! You can find it as a gist at http://gist.github.com/443124. Feel free to clone, improve and share! This code need some refactoring for sure but I did not have time yet and many people where asking for it. Feel free to improve it and share it ;-)

Stay tuned, we will publish some new widgets in the coming months...

11 comments:

  1. Hi. It looks great!

    Can you put an example with the schema and the use of the widget please!

    Thanks!

    ReplyDelete
  2. Uhmmmm... ¿why is 'choices' required?

    Isnt the way to get the choices returned by 'source' script?

    ReplyDelete
  3. how about i18n ???

    ReplyDelete
  4. any tutorial or demo????
    looks fantastic BTW

    ReplyDelete
  5. required 'choices' really look weird when having 'source'..

    and a few full working examples would be VERY nice ;)

    ReplyDelete
  6. Hmm. Getting a JS error in firebug "this.menu is undefined", line 321 in jQuery ui 1.8.5.

    I've deployed it as such in my form class:
    $this->widgetSchema['assessment_unit_list'] = new sfWidgetFormChoiceAutocomplete(array(
    'choices' => AssessmentUnitTable::getSortedByName($deptParam),
    'source' => "/teaching_component/autocomplete?limit=15"
    ));

    And then in my teaching_component actions class:

    public function executeAutocomplete($request)
    {
    $this->getResponse()->setContentType('application/json');

    $q = "%" . $request->getParameter('q') . "%";

    $limit = $request->getParameter('limit');

    $dql = Doctrine_Query::create()
    ->select('p.*')
    ->from('TeachingComponent p')
    ->where('p.subject LIKE ?', array($q))
    ->orderby('p.subject, p.department_id ASC')
    ->limit($limit);
    $this->rows = $dql->fetchArray();

    $tc = array();
    foreach ($this->rows as $row)
    {
    $tc[$row['id']] = (string) $row['subject'];

    if ($row['assessment_unit_code']) $tc[$row['id']] .= (string) " [".$row['assessment_unit_code']."]";

    $q = Doctrine_Query::create()
    ->select('d.department_name')
    ->from('Department d')
    ->where('d.id = '.$row['department_id']);

    $department = $q->execute();

    $tc[$row['id']] .= " - ".$department[0];
    }

    return $this->renderText(json_encode($tc));
    }

    ... Seems to return the JSON but no pop-up dropdown happens. I'm no expert, however, in case you hadn't already noticed!

    ?:(

    ReplyDelete
  7. OK, I'm officially I n S A N e trying to implement this now.

    I've concluded firebug is sufficiently complex to become sentient and steer all man-made computer-controlled machines to wrestle dominance of the solar system from the three-fingered hands of our silent alien masters.

    ... Any clues?? :S

    ReplyDelete
  8. $tc = array();
    foreach ($this->rows as $row) {
    $ar = array();
    $ar['id'] = $row['id'];
    $ar['label'] = $row['nazwa'];
    $ar['value'] = $row['nazwa'];
    $tc[] = $ar;
    }

    return $this->renderText(json_encode($tc));

    It works

    ReplyDelete
  9. everything seems to work fine, but when i submit the form the values i marked don't appear in the screen neither in the database.

    $this->widgetSchema['relatorio_has_a0_list'] = new sfWidgetFormChoiceAutocomplete(array(
    'choices' => A0Peer::doSelect(new Criteria()),
    'source' => "/a0_autocomplete/15",
    "help" => "Procurar a0..."
    ));


    what am i doing wrong?

    ReplyDelete
  10. thanks, very good! but I have a problem... In the list of checkboxes I can select one element only. Why? I need to configure something else?

    ReplyDelete