field_data.each si not a function Joomla 3.7

by Leoalv   Last Updated April 26, 2017 22:10 PM

I have a module that uses javascript to clone fields, select layouts and get data from the database, which has stopped working in Joomla 3.7. The error that shows me is the following.

field_data.each si not a function

The problem is only in the administration and when the new ISIS template is used, because with Hathor it works correctly. The javascript code is as follows.

MultimoduleInit = function ($) {

var $allElems, activeType, $activeType, configs = null;


initConfigForm = function (bindEvent) {
    // Update config data
    if (!configs) {
        configs = getJSon(decodeHtml($('#multimodule-config').val()));
    }
    // update value for layout param
    if (configs[':type'] || configs[':layout']) {
        $('#multimodule-type').val(configs[':type'] ? configs[':type'] : configs[':layout']);
        if ($('#multimodule-type').val() == null) {
            $('#multimodule-type').val('');
        }
    }
    // display correct form
    displayConfig(bindEvent);
    switchLayout();
}

displayConfig = function (rebind) {
    tmp = $('#multimodule-type').val().split(':');
    activeType = tmp.length == 1 ? tmp[0].trim() : tmp[1].trim();
    $activeType = $('#multimodule-' + activeType);
    $('.multimodule-layout-config').addClass('hide');
    $activeType.removeClass('hide');

    // update active form
    updateActiveForm (rebind);

    // remove all required attribute
    $allElems.removeClass('required');
    $allElems.prop ('disabled', true);

    // add required for selected layout only
    $activeType.find('input, textarea, select').prop('disabled', false).each(function () {
        if ($(this).data('required')) $(this).addClass('required');
    });

    // fix runtime elements
    fixSwitchType ();
};

setVal = function (elem, value) {
    var type = elem[0].type,
        tag = elem[0].tagName;
    if (type == 'radio' || type == 'checkbox') {
        elem.removeAttr('checked').filter('[value="' + value + '"]').prop('checked', true);
    } else if (tag == 'TEXTAREA') {
        elem.html(value);
    } else if (tag == 'SELECT') {
                elem.val(value);
                    if (elem.val() != value) {
                            elem.val(elem.find ('option:first').val());
                    }
            } else {
        elem.val(value);
    }
};

getVal = function (elem) {
    var fname = elem.name,
        type = elem.type,
        $field = (type == 'radio' || type == 'checkbox') ? $('input[name="' + fname + '"]:checked') : $('[name="' + fname + '"]'),
        value = $field.length < 2 ? $field.val() : $field.map(function () {
            return $(this).val()
        }).get();

    return value;
};

getVal2 = function (elem) {
    var name = $(elem).data('name'),
        type = elem.type,
        $fields = $allElems.filter(function () {
            return $(this).data("name") == name
        });
    if ((type == 'radio' || type == 'checkbox')) $fields = $fields.filter(':checked');

    return $fields.map(function () {
        return $(this).val()
    }).get();
}

updateVal = function (fname) {
    var elem = $allElems.filter(function () {
            return $(this).data("name") == fname
        })[0];
    if ($(elem).data('ignoresave')) return ;
    var val = getVal2(elem),
        layout = $(elem).parents('.multimodule-layout-config'),
        layout_name = layout.attr('id').substr('multimodule-'.length);
    if (!configs[layout_name]) configs[layout_name] = {};
    configs[layout_name][fname] = val;
}

getJSon = function (str) {
    var result = {}
    try {
        result = JSON.parse(str.trim());
    } catch (e) {
        return {};
    }
    return $.isPlainObject(result) ? result : {};
}

encodeHtml = function (str) {
    return String(str)
        .replace(/</g, '((')
        .replace(/>/g, '))');
}

decodeHtml = function (str) {
    return String(str)
        .replace(/\(\(/g, '<')
        .replace(/\)\)/g, '>');
}

cloneRow = function (row, idx, $lastrow, bindEvents) {
    var $newrow = $(row).clone(true, true),
        atags = $newrow.find('a');

    // insert new row
    $newrow.insertAfter($lastrow);

    // find item with id and change it
    $newrow.find('input, select, textarea').each(function () {
        var newid = this.id + '_' + idx,
            oldid = this.id;
        // update label for
        $newrow.find('[for="' + oldid + '"]').attr('for', newid).attr('id', newid + '-lbl');
        this.id = newid;
        this.name = $(this).data('name') + '[' + idx + ']';

        // find a tag and update id
        atags.each(function (i, a) {
            if (a.href) a.href = a.href.replace('fieldid=' + oldid + '&', 'fieldid=' + newid + '&');
            if ($(a).attr('onclick')) $(a).attr('onclick', $(a).attr('onclick').replace('\'' + oldid + '\'', '\'' + newid + '\''));
        });

        // update image preview tips
        regex = new RegExp('"'+oldid+'_preview', 'gm');
        var oldtips = $(row).find ('.hasTipPreview'),
            newtips = $newrow.find ('.hasTipPreview');
        oldtips.each (function (i, tip) {
            if (tip.retrieve && tip.retrieve ('tip:title') && tip.retrieve ('tip:text') && tip.retrieve ('tip:text').match (regex)) {
                newtips[i].store('tip:title', tip.retrieve ('tip:title'));
                newtips[i].store('tip:text', tip.retrieve ('tip:text').replace (regex, '"'+newid+'_preview'));
            } else if (tip.title.match (regex)) {
                newtips[i].title = tip.title.replace(new RegExp('"'+oldid+'_preview', 'gm'), '"'+newid+'_preview');
            }
        });

        // update button
        var  $button = $newrow.find ('#' + oldid + '_img');
        if ($button.length) {
            $button.attr('id', newid + '_img');
        }
    });

    // update tips
    var oldtips = $(row).find ('.hasTip'),
        newtips = $newrow.find ('.hasTip');
    oldtips.each (function (i, tip) {
        if (tip.retrieve ('tip:title')) {
            newtips[i].store('tip:title', tip.retrieve ('tip:title'));
            newtips[i].store('tip:text', tip.retrieve ('tip:text'));
        } else {
            newtips[i].title = tip.title;
        }
    });

    // rebind events for image button & tips
    if (bindEvents) {
        // enable modal
        SqueezeBox.assign($newrow.find('a').filter('.modal').get(), {
            parse: 'rel'
        });
        // init new tips
        new Tips($newrow.find('.hasTip').get(), { maxTitleChars: 50, fixed: false});
        new Tips($newrow.find('.hasTipPreview').get(), { maxTitleChars: 50, fixed: false, onShow: jMediaRefreshPreviewTip});
    }

    // fix for runtime elements after clone
    fixCloneRow ($(row), $newrow);

    return $newrow;
}

switchLayout = function () {
    var layout = $activeType.find('.multimodule-layouts').val();
    // unhide and add required if needed
    $activeType
        .find ('.control-group, .multimodule-group')
        .removeClass ('hide')
        .find ('input, select, textarea')
        .prop('disabled', false)
        .filter (function (){return $(this).data('required')})
        .addClass ('required');

    // hide, disable and remove required elements not used for selected layout
    $activeType
        .find ('.control-group, .multimodule-group')
        .filter(function(){
                var layouts = $(this).data('layouts');
                return layouts && !layouts.match(new RegExp('(^|,)\\s*' + layout + '\\s*(,|$)', 'i'));
            })
        .addClass ('hide')
        .find ('input, select, textarea')
        .prop('disabled', true)
        .removeClass ('required');
}

updateActiveForm = function (rebind) {
    // update value to form
    if (!activeType || !$activeType) return;
    var data = configs[activeType] ? configs[activeType] : getJSon(decodeHtml($activeType.find('[name="multimodule-sample-data"]').val()));
    if (!data) return ;
    // get all fields in this layout
    var fields = $activeType.find('input, select, textarea');

    $.each(data, function (field_name, value) {
        var elem = $activeType.find('[name="' + field_name + '"]'),
            field_data = data[field_name],
            group = elem.parents('.multimodule-group');
        if (!elem.length) return;
        if ($.isArray(field_data) && group.hasClass('multimodule-multiple')) {
            // find this field
            var $rows = group.find('.multimodule-row');
            if ($rows.length && field_data.length > $rows.length) {
                var $lastrow = $rows.last();
                for (var i = $rows.length; i < field_data.length; i++) {
                    // clone row
                    var $newrow = cloneRow($rows[0], i, $lastrow, rebind);
                    $lastrow = $newrow;
                }
            }
            $rows = group.find('.multimodule-row');
            // check & update data
            // rows = group.find  ('.multimodule-row');
            field_data.each(function (val, i) {
                var elem = $($rows[i]).find('input, select, textarea').filter(function () {
                    return $(this).data('name') == field_name
                });
                setVal(elem, val);
            });
        } else {
            setVal(elem, $.isArray(field_data) ? field_data[0] : field_data);
        }
    });
    // get all form elements
    $allElems = $('.multimodule-layout-config').find('input, select, textarea');

    $activeType.trigger ('change');
}

fixSwitchType = function () {
    // update chosen for active status
    $('#multimodule-type').trigger ('liszt:updated');
    $activeType.find ('select').trigger ('liszt:updated');
}

fixCloneRow = function ($oldrow, $newrow) {
    // fix for jQuery Chosen
    if ($newrow.find('select').hasClass('chzn-done')) {
        // remove chosen if found and recreate it
        $newrow.find('.chzn-container').remove();
        $newrow.find('select').data('chosen', null).chosen();
    }

}


getData = function () {
    configs = {}
    configs[':type'] = $('#multimodule-type').val();
    var $elems = $activeType.find ('input, select, textarea'),
        names = $elems.map(function(){ return $(this).data('name') }).get();
    names.each(function (fname, i) {
        updateVal(fname);
    });

    return encodeHtml(JSON.stringify(configs));
}



confirm = function (actions) {
    var confirmbox = $('#mm-dialog-confirm');
    if (!confirmbox.length) {
        confirmbox = $('<div id="mm-dialog-confirm" title="Confirm">Are you ok ?</div>').appendTo ('body');
    }
    confirmbox.dialog({
        resizable: false,
        modal: true,
        height: 200,
        width: 300,
        buttons: {
            "Yes": function () {
                $(this).dialog('close');
                actions['yes']();
            },
            "No": function () {
                $(this).dialog('close');
                if (actions['no']) actions['no']();
            }
        }
    });
}

// get all form elements
$allElems = $('.multimodule-layout-config').find('input, select, textarea');

$allElems.each(function () {
    var $this = $(this);
    if ($this.hasClass('required')) {
        $this.data('required', 1).removeClass('required');
    }
    $this.data('name', this.name);
});

initConfigForm (false);

// switch config when change type
$('#multimodule-type').on('change', function () {
    displayConfig(true);
});

// show/hide fields when change layout
$('.multimodule-layouts').on('change', function () {
    switchLayout();
});

// bind submit event for form
document.adminForm.onsubmit = function () {
    configs = {}
    configs[':type'] = $('#multimodule-type').val();
    var $elems = $activeType.find ('input, select, textarea'),
        names = $elems.map(function(){ return $(this).data('name') }).get();
    names.each(function (fname, i) {
        updateVal(fname);
    });

    // encode HTML & update to hidden var
    $('#multimodule-config').val(encodeHtml(JSON.stringify(configs)));
}

// bind event for btn-add, btn-del
$('.multimodule-btn-add').on('click', function () {
    var rows = $(this).parents('.multimodule-group').find('.multimodule-row'),
        newrow = cloneRow(rows.first(), rows.length, rows.last(), true);

    // update $allElems
    $allElems = $('.multimodule-layout-config').find('input, select, textarea');
});

$('.multimodule-btn-del').on('click', function () {
    var $this = $(this),
        $row = $this.parent(),
        $fieldset = $row.parent();
    confirm ({
        'yes': function (){
            // move this button out
            $this.appendTo($fieldset);
            $row.remove();
            // update $allElems
            $allElems = $('.multimodule-layout-config').find('input, select, textarea');
        }
    })
});

// hover event for row
$('.multimodule-row').on('mouseenter',function () {
    if ($(this).is($(this).parent().find('.multimodule-row').first())) return;
    // check if this is the last row, do nothing
    if ($(this).parent().find('.multimodule-row').length < 2) return;
    $(this).parent().find('.multimodule-btn-del').appendTo($(this));
}).on('mouseleave', function () {
    $(this).find('.multimodule-btn-del').appendTo($(this).parent());
});

// build done, fire change events
$(document).ready(function () {
    $('.multimodule-layout-config').trigger('change');
})

// store this
$.data(document, 'MultimoduleDATA', this);

}

The error shows it in line 243 and piece of code is.

field_data.each(function (val, i) {
var elem = $($rows[i]).find('input, select, textarea').filter(function () {
    return $(this).data('name') == field_name
});
setVal(elem, val);

});

Trying to solve it I found that if I delete the new ISIS media.php file, it works correctly Location of media.php:

administrator/templates/isis/html/layouts/joomla/form/field

Any Idea or solution? I thank you in advance. If someone wants to do tests I can deliver the complete module.



Related Questions


Can't insert intro/full article image

Updated July 25, 2016 08:04 AM

Mixing PHP variables and JS variables in output

Updated March 23, 2016 08:04 AM

Show backend component on admin index

Updated March 26, 2015 07:25 AM


Assigning ID to javascript function

Updated March 23, 2016 08:04 AM