kartik-v / yii2-widget-select2

Enhanced Yii2 wrapper for the Select2 jQuery plugin (sub repo split from yii2-widgets).
http://demos.krajee.com/widget-details/select2
Other
323 stars 145 forks source link

Ajax Implementation with Activeform not showing saved item #202

Closed dbd5 closed 7 years ago

dbd5 commented 7 years ago

Prerequisites

Steps to reproduce the issue

  1. Standard configuration of ActiveForm with Ajax data source
  2. Open form for update
  3. Select any item and Save (Item is CONFIRMED saved)
  4. Reopen the form for update

Expected behavior and actual behavior

When I follow those steps, I see...

The widget is expected to load and display the saved value but it shows nothing. However, if you replace the widget with a text box, the text box displays the value in the model.

Environment

Browsers

Operating System

Libraries

Isolating the problem

amlopezalonso commented 7 years ago

I'm trying to workaround a closely related issue in my app, so if you post your view code maybe I can see what is happening.

dbd5 commented 7 years ago

Hi @amlopezalonso ,

The code follows below, but please note the following;

`<?php

use yii\bootstrap\ActiveForm; use yii\helpers\Html; use yii\helpers\Url; use yii\web\JsExpression; use kartik\select2\Select2;

/**

$this->registerJs(new JsExpression(' (function ($) { "use strict";

$("#profile-country_id").on("select2:selecting", function () {
    $("#profile-region_id").removeAttr("disabled");
    $("#profile-city_id").removeAttr("disabled");
});

})(jQuery); '));

?>

<?php $this->beginContent('@dektrium/user/views/admin/update.php', ['user' => $user]) ?>

<?php $form = ActiveForm::begin([
    'layout' => 'horizontal',
    'enableAjaxValidation' => true,
    'enableClientValidation' => false,
    'fieldConfig' => [
        'horizontalCssClasses' => [
            'wrapper' => 'col-sm-9',
        ],
    ],
]); ?>

<?= $form->field($profile, 'name') ?>
<?= $form->field($profile, 'public_email') ?>
<?= $form->field($profile, 'website') ?>
<?= $form->field($profile, 'location') ?>
<?= $form->field($profile, 'gravatar_email') ?>
<?= $form->field($profile, 'bio')->textarea() ?>

<?= $form->field($profile, 'country_id')
    ->widget(Select2::className(), [
        'data' => [],
        'theme' => Select2::THEME_DEFAULT,
        'options' => ['placeholder' => 'Select a Country ...'],
        'pluginOptions' => [
            'ajax' => [
                'url' => Url::to('/dbload/countries'),
                'dataType' => 'json',
                'data' => new JsExpression('function(params) {return {q:params.term}}')
            ],
        ],
    ])

// $form->field($profile, 'country_id')
?>

<?= $form->field($profile, 'region_id')
    ->widget(Select2::className(), [
        'data' => [],
        'theme' => Select2::THEME_DEFAULT,
        'options' => ['placeholder' => 'Select a Region ...'],
        'disabled' => true,
        'pluginOptions' => [
            'ajax' => [
                'url' => Url::to('/dbload/regions'),
                'dataType' => 'json',
                'data' => new JsExpression('function(params) {return {
                    q: params.term, 
                    country_id: $("#profile-country_id").val()
                }}')
            ],
        ],
    ])

// $form->field($profile, 'region_id')

?>

<?= $form->field($profile, 'city_id')
    ->widget(kartik\select2\Select2::className(), [
        'data' => [],
        'theme' => Select2::THEME_DEFAULT,
        'options' => ['placeholder' => 'Select a City ...'],
        'disabled' => true,
        'pluginOptions' => [
            'ajax' => [
                'url' => Url::to('/dbload/cities'),
                'dataType' => 'json',
                'data' => new JsExpression('function(params) {return {
                    q:params.term,
                    country_id: $("#profile-country_id").val(),
                    region_id: $("#profile-region_id").val()
                }}')
            ],
        ],
    ])

// $form->field($profile, 'city_id')

?>

<div class="form-group">
    <div class="col-lg-offset-3 col-lg-9">
        <?= Html::submitButton(Yii::t('user', 'Update'), ['class' => 'btn btn-block btn-success']) ?>
    </div>
</div>

<?php ActiveForm::end(); ?>

<?php $this->endContent() ?> `

amlopezalonso commented 7 years ago

Is 'data' => [], really needed? Try commenting it out and then insert:

'initValueText' => $profile->countryName, (or whatever your attribute is)

right below widget's theme entry.

dbd5 commented 7 years ago

Hi @amlopezalonso ,

It displayed - thanks for the suggestion.

However, consider that the control is bound to the model and the model loads the data as expected - the complaint is that is that the control doesn't render the data that is available on the model.

In my review of previous posts on similar issues, @kartik-v seemed to always suggest that people should read the manual and ensure that they assign data to the appropriate attribute in their model.

Therefore this looks very much like a workaround than proper configuration. I will leave this issue open for now.

amlopezalonso commented 7 years ago

mmmm, I'm not 100% sure as I'm not a Yii2 guru by any means but I would bet that autoloading refers exclusively to Yii2's internal AJAX way of handling form data. Select2 has its own AJAX way, and that's the reason why there is a data option that could be placed in three different positions inside widget (top level, pluginOptions and pluginOptions/ajax). So I suspect that if you work your input ala pure Select2 way, you must use initValueText.

With non-AJAX Select2 you just use top-level data and then your stuff is autoloaded for sure. But that's not your use case.

dbd5 commented 7 years ago

More surprising still, as expected the data returned from Ajax is json encoded array pairs of id and text but the widget displays the id part. Shouldn't the widget be displaying the text part?

kartik-v commented 7 years ago

Note that for ajax based data loading feature of Select2 plugin - the dropdown does not initialize the initial value displayed itself .

The model attribute value will be taken internally as the value automatically.

But the displayed value for initialization for ajax based scenarios will need to be set. This has been enabled specially in this yii2 extension as a widget property initValueText. Hope this makes it clear on when you need to set this.

amlopezalonso commented 7 years ago

Hi Kartik:

Today I raised a question in StackOverflow:

https://stackoverflow.com/questions/42651402/yii2-kartiks-detailview-and-select2-loading-ids-not-text

Maybe this could be related to what we are discussing here? Or is it rather a DetailView usage issue?

Thanks a lot, Antonio

El 7 mar. 2017 16:18, "Kartik Visweswaran" notifications@github.com escribió:

Note that for ajax based data loading feature of Select2 plugin - the dropdown does not initialize the initial value displayed itself .

The model attribute value will be taken internally as the value automatically.

But the displayed value for initialization for ajax based scenarios will need to be set. This has been enabled specially in this yii2 extension as a widget property initValueText. Hope this makes it clear on when you need to set this.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/kartik-v/yii2-widget-select2/issues/202#issuecomment-284770189, or mute the thread https://github.com/notifications/unsubscribe-auth/AJJaOUZHbIaTgqPs0o13-KtVEyZzHdaBks5rjYM9gaJpZM4MVSsL .

kartik-v commented 7 years ago

Yes you need to set initValueText for such scenarios... for multi select it would be an array

dbd5 commented 7 years ago

Thanks @kartik-v,

I'm happy to initialize initValueText to anything statically but my contention is that once the form loads the model and the attribute is known, I expect the Widget to display the text part of the returned data.

In my case, the widget is bound to city_id for instance. Ajax return the correct text but the Widget loads the and displays city_id rather than the text. This cannot be the correct behavior -- and please do not close this issue, please enlighten me.

kartik-v commented 7 years ago

As I mentioned you are using the ajax property of the plugin which is a plugin's capability to create the dropdown options via ajax - which means it will not use the normal way of initializing select and creating dropdown options via HTML select markup. This has no relation to the values you are setting on init.

Had closed this as this is not an issue and expected occurence with the plugin. Let know if you have any other suggestions and have kept it open till I hear back.

dbd5 commented 7 years ago

Since this is plugin specific you need to write your own javascript to do this initialization for an ajax scenario. As an alternative, this extension has provided a property of initValueText to set this yourself for easy intialization of the displayed text.

Thanks @kartik-v, I see the constraints. A key consideration must be usability and intuitiveness as seen by the app user (not the app developer). In the case in consideration 3 of the widgets are setup in the form for country_id -> region_id -> city_id and their default values set with initValueText. After the user selects country, and / or region, the city is still showing the value initialized with initValueText. It is expected that he will proceed to select the city to complete the form but at this time he has a City that is not related to the currently selected country and region. At this stage he could select the correct City and save the form or because of the value already in City, he may click save if like most users if he is not paying attention but we cannot assume the user will do the right thing.

That leaves these options (a) make initValueText blank in the 3 widgets (b) make a correct initial assumption of of the user's Country, Region and City (3) Somehow reset the values of Region and City once Country changes.

Is there a way to achieve (3) with Yii2-Widget-Select2 or will you recommend to use your Depdrop instead in my scenario?

Thanks for your work on these widgets and your insights in these discussions.

Adam

kartik-v commented 7 years ago

After the user selects country, and / or region, the city is still showing the value initialized with initValueText.

This is an app coding scenario for your use case. You want to change values of one select dropdown based on another dropdown dynamically at runtime... which means it essentially is a javascript coding that will change the displayed values of one input based on another input value. So this is actually not related to the Select2 plugin OR Select2 extension and a programming scenario for you to handle.

Yes DepDrop widget was created for handling such scenarios above in a generic reusable manner. You may want to look at that kartik-v/yii2-widget-depdrop.

I am closing this issue here... it may help if you can post any such programming queries on the webtips forum or in the comments & discussions zone for the Select2 extension for more people to participate and help.

dbd5 commented 7 years ago

Thanks once again