Welcome Guest, Not a member yet? Register   Sign In
Validation causes multi select to lose values
#1

[eluser]joelkinzel[/eluser]
First off, let me say that I tried to search here and Stack Overflow for an answer to this, but I can't seem to find anything that deals with this particular issue. When I did post on SO the only answer was to "restructure" my application (which isn't an option at this point).

My application is set up in a manner where the input is not being built in the controller, bur rather in a model, which is called by the view (yes, I know, it isn't proper MVC, but I don't have a choice at this point, I need to finish the application in minimal time so changing that isn't an option at this point). The appropriate code is then returned based on what is passed to the model. The "form builder" model uses the form helper to build form elements based on data provided to it by the view (which in turn gets it from the controller, which in turn gets it from other models, which gets it from the database).

View:
Code:
foreach($category->questions as $question){
    $_args = array(
        'user'=>$user,
'question'=>$question
    );
    $fb = new Form_builder($_args);
    $attributes = array();
    if( ! $user->is_admin() && $question->admin_only){
$attributes['disabled'] = 'disabled';
    }
    if(form_error(underscore($question->question_text) . '[response]')){
$attributes['error'] = 'error';
    }
    echo $fb->build_input($attributes);  
}

Model (form_builder.php):
Code:
public function build_input(array $args = NULL){
    $_input_data = array(
         'name' => underscore($this->question->question_text).'[response]',
         'id'      => 'question-' . underscore($this->question->question_id),
         'class' => $this->question->required === '1' ? 'required' : ''
    );
          
    if ($args){
        if(in_array(strtolower('disabled'), $args)){
     $_input_data['disabled'] = 'disabled';
}
if(in_array(strtolower('readonly'), $args)){
     $_input_data['readonly'] = 'readonly';
}
if(in_array(strtolower('error'), $args)){
     $_input_data['class'] .= ' error';
}
    }

    if(strtolower($this->question->question_text) === 'authors'){
         return $this->_get_author_multiselect($_input_data);
     }
}
private function _get_author_multiselect($_input_data){
    $faculty = new Faculty();
    $response = $this->_get_user_response();
    $pre_selected;
    if(is_array($response)){
        foreach($response as $row){
     $pre_selected[$row->response_int] = $this->user->get_display_name($row->response_int, TRUE);
}
     } else if(is_object($response)) {
        $pre_selected[$response->response_int] = $this->user->get_display_name($response->response_int, TRUE);
    } else {
$pre_selected[$this->user->get_identity()] = $this->user->get_display_name($this->user->get_identity(), TRUE);
    }

    $additional_attributes = '';
    $_input_data['id'] = 'right-select';
    foreach($_input_data as $attribute=>$value){
$additional_attributes .= $attribute . '="' . $value . '" ';
    }
    $html = '<div class="fac-left"><span>Radiology Faculty</span>';

    $html .= form_multiselect('all-authors', set_value('all-authors', $faculty->get_all_for_multiselect()), array(), 'id="left-select"');

    $html .= '</div><div class="fac-actions"><button type="button" class="btn" id="add-fac">Add</button><button type="button" class="btn" id="remove-fac">Remove</button></div><div class="fac-right"><span>Selected Authors</span>';

    $html .= form_multiselect('authors[response][]', set_select('authors[response][]', $pre_selected, TRUE), array(), $additional_attributes);

    $html .= '</div>';

    return $html;
  }

When the page loads, the items are populated correctly, however when the user submits the form, if there are any errors, the selection is lost (or just one of the items is selected). Other items that are built using the same process, don't lose their values after failed validation, just multi selects.
#2

[eluser]Aken[/eluser]
set_value() will never return an array. Just look at the code, it makes that pretty obvious:

Code:
// 2.1.3, system/libraries/Form_validation.php, line 736:

// If the data is an array output them one at a time.
//     E.g: form_input('name[]', set_value('name[]');
if (is_array($this->_field_data[$field]['postdata']))
{
return array_shift($this->_field_data[$field]['postdata']);
}

There is no appropriate helper for repopulating multiselects at this time. You should just use the post data directly. If you think it should be added, you should submit an issue or pull request on Github. Smile

By the way, it also looks like you're passing the selected options in the parameter that is supposed to be all available options here:

Code:
$html .= form_multiselect('authors[response][]', set_select('authors[response][]', $pre_selected, TRUE), array(), $additional_attributes);

The parameters should be $name, $options, $selected, $extra.
#3

[eluser]joelkinzel[/eluser]
Yeah I figured that was the case, but I was hoping I was missing something in the docs. Also, thanks for pointing that out!

Do you know if anyone has perhaps done an example that might extend the form_validation to allow an array to be passed?
#4

[eluser]Aken[/eluser]
Not off hand, but it's incredibly easy. Just replicate the set_value() function and remove that chunk quoted above. Then it will output the POST value if it's a string or array. You can replace the set_value() function or rename it to something new, whatever you like.




Theme © iAndrew 2016 - Forum software by © MyBB