2

I am trying to create a Calendar field in Joomla 3.9 inside my custom component. Since I am framing this inside an AJAX script, I can't use the XML form.

Below is the code I am using. The field gets displayed, but when I click, the popup is not coming. There is no error captured in the console.

$html .= "<div class='controls'>";
$html .= JHtml::_('calendar', '', "jform_field_4", "jform_field_4", '%Y-%m-%d', '');
$html .= "</div>";

Following are the inserts which are already done:

<link href="/jschool/media/system/css/fields/calendar.css" rel="stylesheet">
<script src="/jschool/media/system/js/fields/calendar-locales/en.js"></script>
<script src="/jschool/media/system/js/fields/calendar-locales/date/gregorian/date-helper.min.js"></script>
<script src="/jschool/media/system/js/fields/calendar.min.js"></script>

HTML content rendered as below:

<div class="field-calendar">
    <div class="input-append">
        <input type="text" id="jform_field_4" name="jform_field_4" value="" data-alt-value="" autocomplete="off">
        <button type="button" class="btn btn-secondary" id="jform_field_4_btn" data-inputfield="jform_field_4" data-dayformat="%Y-%m-%d" data-button="jform_field_4_btn" data-firstday="0" data-weekend="0,6" data-today-btn="1" data-week-numbers="1" data-show-time="0" data-show-others="1" data-time-24="24" data-only-months-nav="0" title="Open the calendar">
        <span class="icon-calendar" aria-hidden="true"></span>
        </button>
    </div>
</div>

On deep diving the HTML code, I found the block missing in the rendered HTML.

<div class="js-calendar" style="direction: ltr; position:.....
.....
.....
</div>

Any idea why this block of code is missing and why the popup is not coming?


Full Flow of the code is as below

Views

I got the load template to load profile_fields

echo $this->loadTemplate('profile_fields');

AJAX

Method called at page load

function getFields(){
    jQuery('#ajax_loader_image_2').show();
    jQuery('#task').val('profile.getFields');
    var dataString = jQuery("#profile-form").serialize();

    return jQuery.ajax({
        type: 'POST',
        url: 'index.php',
        data: dataString,
        success: function(result){
        },
        error: function(result){
        }
    });
}

Controller

That calls the model to load the HTML content

public function getFields(){
    JFactory::getDocument()->setMimeEncoding( 'application/json' );
    $model = $this->getModel();
    $response = $model->getFields();
    echo $response ;
    JFactory::getApplication()->close();
}

Model to frame the Calendar

public function getFields() {

    $field <-- this is an object contains an uniqe id, type etc...
    $html_content = $this->convertFieldHtml ( $field );
    return $html_content;
}


private function convertFieldHtml($field) {
    $field_type = $field->fldtype_html_field;
    $html = '';

    $properties = $this->getFieldProperties ( $field );

    switch ($field_type) {
        case 'date' :
            $html = $this->loadDateField ($properties, $field );
            break;
    }
    return $html;
}

private function loadDateField($properties, $field) {

    $html = '';
    $html .= "<div class='control-group'>";

    // Set the control
    $html .= "<div class='controls'>";

    $attribs = array();
    $attribs['size']=18;
    $attribs['maxlength']=20;

    $html .= JHtml::calendar('', "jform_field_".$field->field_id, "jform_field_".$field->field_id, '%Y-%m-%d',$attribs);
    //$html .= JHtml::_('calendar','', "jform_field_".$field->field_id, "jform_field_".$field->field_id, '%Y-%m-%d',$attribs);

    if ($field->field_tooltip) {
        $html .= "<div>" . $field->field_tooltip . "</div>";
    }
    $html .= "</div>";

    $html .= "</div>";

    return $html;
}
  • On your rendered page use your browsers development tool and change the type="text" to type="date" and see if your calendar pops up. Last week I was trying to remove the pop up calendar and it came down to the field type and how each browser handles it slightly different. – Irata Dec 1 '19 at 11:38
  • Could you please try to add the calendar field in the standard way and see it that way: JHtml::calendar($value, $name, $id, $format= '%Y-%m-%d', $attribs = array()); – Zollie Dec 1 '19 at 12:18
  • @Zollie tried both the ways and behavior is same. No javascript error in the console and no popup comes. – Malaiselvan Dec 1 '19 at 13:49
  • @Irata tried changing the type to date and that doesnt make any difference. – Malaiselvan Dec 1 '19 at 13:50
  • How do you frame this inside an ajax script? It has something to do with that probably, since your code looks OK. – Zollie Dec 1 '19 at 19:01
1

After testing this issue few times, you can realize that via the ajax call the Calendar HTML fields are created but it will not trigger the JoomlaCalendar javascript methods which are needed to create this field fully functional.

So this is how it worked for me by creating a new JoomlaCalendar object from the loaded HTML fields:

  1. you need to create a simple, empty HTML div within your html form and we should add the calendar field inside this div:

    <div class="datefield1" id="datefield1"> </div>

(You can create this <div> with jQuery too if you would like to or you can wrap the html calendar fields in a <div> in your model as you do it already, but for sure it works if the div is there before the ajax call in the DOM).

  1. You have to extend you ajax call script with few lines:

    function getFields(){
        jQuery('#ajax_loader_image_2').show();
        jQuery('#task').val('profile.getFields');
        var dataString = jQuery("#profile-form").serialize();
    
    return jQuery.ajax({
        type: 'POST',
        url: 'index.php',
        data: dataString,
        success: function(data){
           jQuery('#datefield1').html(data);
           let myDateField1 = document.getElementById('datefield1');
           new JoomlaCalendar(element = myDateField1);
        },
        error: function(result){
        }
        });
    }
    

You see that I just added 3 lines to your jQuery/ajax call script. And few notes about that:

1. I do not think that the request type has to be POST since there is no important data there to be posted, so the request type could be GET. We maybe do not need to send #profile-form data to get the calendar field from you model (I do not see your full requirements regarding this, so this is just a suggestion).

2. In the first line of the success function we add the ajax returned html data from our model to our previously created <div> thus our html calendar field is built. (And the reason that it is not functional is because it is not triggering any more javascript at this point which were needed to get a fully functional calendar field).

3. In the next two lines of success function We define a new javascript object with selecting our created (wrapper) <div> which can now be a valid element for creating a new JoomlaCalendar object with that (it works if the required joomla calendar javascripts are loaded as you already have them loaded on your page).

And you should have a fully functional JoomlaCalendar field. (it’s tested).

EDIT

Just to make sure the above is not misunderstood. The main question is: how to create a Joomla Calendar form field loaded via an ajax call? I'd like to place here a simple clear version of codes based on the question to test the whole thing.

The function in controller(profile) of the view (profile):

public function getFields() {
          JFactory::getDocument()->setMimeEncoding( 'application/json' );
          $model = $this->getModel();
          $response = $model->getFields();          
          echo $response;          
          JFactory::getApplication()->close();
      }

the function in the model(profile) called by the controller:

public function getFields() {
        $newDate = date("Y-m-d H:i:s");
        $myDateField = JHtml::calendar($newDate, "field-calendar-150", "jform-field-150", '%Y-%m-%d');
        return $myDateField;
    }

script with the ajax call in the layout:

<script>

function getFields(){
    jQuery('#ajax_loader_image_2').show();    

    return jQuery.ajax({
        type: 'GET',
        url: '/index.php?option=com_mycomponent&view=default_page_html&task=profile.getFields',
        success: function(data){
           jQuery('#datefield1').html(data);
           let myDateField1 = document.getElementById('datefield1');
           let newElement = myDateField1.firstChild;
           new JoomlaCalendar(element = newElement);
        },
        error: function(result){
        }
    });
}

</script>

I have added one extra line in the success function of the ajax call to make sure that the Calendar field works without any JavaScript undefined parentNode error at blur event. So the above is the simple skeleton of creating a fully functional Joomla Calendar field via using ajax.

UPDATE

In your particular case in your test component in script_fields.php your script should be like this:

<script type="text/javascript">

jQuery(document).ready(function(){
    jQuery('#task').val('profile.getFields');

    return jQuery.ajax({
        type: 'GET',
        url: 'index.php?option=com_ajaxdate&task=profile.getFields',

        success: function(result) {
            jQuery('#fields_container').html(result);
            if (jQuery("[class*='field-calendar']")) {
                let newElement = jQuery("[class*='field-calendar']");
                jQuery.each(newElement, function(index, value) {
                    if (! value.querySelector('.js-calendar')) {
                        try {
                            new JoomlaCalendar(element = value);
                        } catch {
                            console.log("JoomlaCalendar instance is already exists for this element");
                        }
                    }
                });
            }
        },
        error: function(result){
            jQuery('#fields_container').html("no custom fields found");
        }
    });

});

</script>

In the above script:

  1. We select all of the DOM elements which has the class name 'field-calendar'. These are obviously the calendar fields in your form.
  2. Then we check if the element has already the JoomlaCalendar object instance applied on or not by checking whether it has a .js-calendar div child already or not.
  3. Then if not, we create a new JoomlaCalendar Object on that div.
| improve this answer | |
  • Sorry, I am out of town for few days... Thanks for your detailed answer. Will check and revert back in couple of days. Thanks. – Malaiselvan Dec 11 '19 at 11:40
  • Hi, thanks for your detailed answer. Unfortunately I am not able to make it work. I created a simple Joomla admin component for this testing. The link of the package is gofile.io/?c=pl2MXJ. Can you please help whenever you got some free time. – Malaiselvan Dec 24 '19 at 10:37
  • @Malaiselvan - I updated my answer with the script you need in your component. I tested that and works well. Please write me a feedback when you applied that. – Zollie Dec 25 '19 at 13:15
  • 1
    you are great man. The solution works perfect. Thanks a ton for resolving this for me. – Malaiselvan Dec 25 '19 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.