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;
}
7
  • 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, 2019 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, 2019 at 12:18
  • @Zollie tried both the ways and behavior is same. No javascript error in the console and no popup comes. Dec 1, 2019 at 13:49
  • @Irata tried changing the type to date and that doesnt make any difference. Dec 1, 2019 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, 2019 at 19:01

1 Answer 1

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.
4
  • Sorry, I am out of town for few days... Thanks for your detailed answer. Will check and revert back in couple of days. Thanks. Dec 11, 2019 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. Dec 24, 2019 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, 2019 at 13:15
  • 1
    you are great man. The solution works perfect. Thanks a ton for resolving this for me. Dec 25, 2019 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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