Widgets not displaying correctly in renderAjax call from main view

Hi… I’ve searched through a number of somewhat similar questions but have been unable to find a clear resolution. I have good luck with widgets on a standard view, however, when I try to display one by updating a section of the DOM via AJAX, I seem to have trouble. Is there a clear and concise example of that somewhere I’m missing perhaps?

I put together a small live example of my problem at this coming link using a DatePicker as my widget example. I have similar results with both the Kartik and JUI DatePickers.
https://glacier.nationalparkschat.com/web/test/index

The initially loaded widget works great. The widget that loads from pushing the “Push Me” button does load, but does not display properly. That’s my issue.

The widget from the url response that is used for the ajax updating does work on it’s own, so I was surprised it didn’t work in the main view. Here is a link to the url for the ajax call that works good on its own.
https://glacier.nationalparkschat.com/web/test/showdatepicker

I did give both widgets their own names and unique id’s in case that’s an issue.

Here are the controller and the 2 views used in this example.

Controller:

<?php
namespace app\controllers;

use yii\web\Controller;

class TestController extends Controller
{
    public function actionIndex()
    {
        return $this->render('index', []);
    }

    public function actionShowdatepicker()
    {
        return $this->renderAjax('showdatepicker',[]);
    }
}

index View

<?php 
// use yii\jui\DatePicker;
use kartik\date\DatePicker;
?>
<style>
table, th, td {
  border: 2px solid black;
}
</style>
<br><br>
<table>
	<tr><td><b>This widget works well</b></td><td><b>Push Button to load next widget</b></td><td><b>This widget loads but doesn't display correctly when used</b></td></tr>
	<tr>
		<td>
			<div id='default'>
			<?php 
                echo DatePicker::widget([
                    'name'  => 'original_widget',
                    'type' => DatePicker::TYPE_COMPONENT_PREPEND,
                    'value'  => '8/24/2022',
                    'id' => 'original_widget_id',
                    'pluginOptions' => [
                        'autoclose' => true,
                        'format' => 'dd/M/yyyy'
                    ]
                ]);
            ?>
			</div>
		</td>
		<td>
			<button type="button" class="myglacier-arrow-button" onclick="showDetails()">Push Me</button>
		</td>
		<td>
			<div id='newDiv'>
				New DatePicker will show here			
			</div>
		</td>
	</tr>
</table>

<script>
function showDetails() {

	const xhttp = new XMLHttpRequest();
  	xhttp.onload = function() {
  		const details = document.getElementById('newDiv');
  	
  		details.innerHTML = this.responseText;
  	}
  	xhttp.open("GET", "/web/test/showdatepicker");
  	xhttp.send();  
}
</script>

showdatepicker AJAX View

<?php 
//use yii\jui\DatePicker;
use kartik\date\DatePicker;

echo DatePicker::widget([
    'name'  => 'new_widget',
    'type' => DatePicker::TYPE_COMPONENT_PREPEND,
    'value'  => '9/25/2023',
    'id' => 'new_widget_id',
    'pluginOptions' => [
        'autoclose' => true,
        'format' => 'dd/M/yyyy'
    ]
]);
?>            
Loaded!

If something jumps out at you, great! Or if there’s some existing documentation that I seem to have missed, I’ll be happy to check that out. I appreciate any help you may have on this one! I’ll provide a good example with the resolution as well once I have one to post as well.

I’m hoping I’m just overlooking something simple here perhaps, but I admit I’m a little baffled at the moment. I’m open to any and all thoughts here…

Thanks again!

Hi.

(on about the JQuery’s DatePicker widget, I haven’t used Kartik’s one this way)

You have to ‘activate’ widget after loading it via ajax.
Try to add to your showDetails() method:

details.innerHTML = this.responseText;
$("{datepicker.id}").datepicker();
1 Like

Hi Bartek… Thank you very much for your reply!

Based on your post, I went with the following for my example knowing that my datepicker’s id in this case was “new_widget_id”

For the JUI DatePicker

  		details.innerHTML = this.responseText;
  		// This Works for JUI DatePicker
  		$("#new_widget_id").datepicker();

For the Kartik DatePicker

  		details.innerHTML = this.responseText;
  		// This Works for Kartik DatePicker
  		$("#new_widget_id").kvDatepicker();

I also used the following link as a reference as well.
https://learn.jquery.com/jquery-ui/how-jquery-ui-works/

I haven’t fully tested submitting its form values around yet (I’ll update again after doing that) but, the calendar part does display properly now for both instances of the different DatePickers, which it was not doing before, so this is a huge step in the right direction!

I updated the live example at the link above as well if that helps anyone else also…

Thanks Bartek! Cheers!

A quick followup…

In my real world scenario, at the time the original page loads, I likely wont know the ID’s of the datepickers that will need to be activated as new ones could be added, I’m opting for a group activation as follows…

Note: this is somewhat specific to the Kartik/Krajee Datepicker now regarding the class name and kvDatepicker function, but i’m sure it would also work for JUI Datepicker as well with the slight adjustments for that.

details.innerHTML = this.responseText;
const elements = document.getElementsByClassName('krajee-datepicker');
for (const element of elements) {
      $(element).kvDatepicker();
}

So far, it seems to be working…

1 Like

One more followup regarding the pluginOptions and pluginEvents of the DatePicker when defined in the widget on the view. Those values don’t stick when displaying the widget by ajax. (In my case anyway.) They work fine if you use the widget on a non-ajax view.

To resolve this, I set my pluginOptions and pluginEvents in the JQuery activation section like this…

	const elements = document.getElementsByClassName('krajee-datepicker');
	for (const element of elements) {
      $(element).kvDatepicker({format: 'M dd, yyyy', autoclose: true,}).on('changeDate', function(e) {
        	saveStartDate(e.target.id.substring(9));
      });    
    }

And that seems to work. I admit I don’t understand why that’s needed exactly, but it does seem to make it work that way, so that’s great.