11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour à vous,

en fait, j'ai trouvé un script javascript intéressant pour taper des tags qui existent et qui n'existent pas.

Cependant, dans le code actuel, la source des codes existants est alimenté via un tableau json :


$('#form-tags-4').tagsInput({
    'autocomplete': {
        source: [
            'apple',
            'banana',
            'orange',
            'pizza'
        ]
    }
});


J'aimerais bien retourner les éléments existants via une requête sur une table.

J'ai donc remplacer le tableau json par :


        $('#form-tags-4').tagsInput({
            'autocomplete': {
                source: function (query, process) {
                    return $.get('item.php', {query: query}, function (data) {
                        return process(data);
                    });
                }
            }
        });


Le problème, c'est que je reçois l'erreur suivante :

Uncaught TypeError: Cannot use 'in' operator to search for 'length' in []
at w (jquery.min.js:2)
at Function.map (jquery.min.js:2)
at t.<computed>.<computed>._normalize (jquery-ui.min.js:8)
at t.<computed>.<computed>._normalize (jquery-ui.min.js:6)
at t.<computed>.<computed>.__response (jquery-ui.min.js:8)
at t.<computed>.<computed>.__response (jquery-ui.min.js:6)
at t.<computed>.<computed>.n (jquery-ui.min.js:6)
at t.<computed>.<computed>.__response (jquery-ui.min.js:8)
at t.<computed>.<computed>.__response (jquery-ui.min.js:6)
at t.<computed>.<computed>.<anonymous> (jquery-ui.min.js:8)


Au niveau de l'url de ma page PHP, voici comment l'appel est fait :

item.php?query%5Bterm%5D=pizza

Le %5B représente la caractère [ et le %5D le caractère ].

En plus, il vient mettre le chaîne de caractères "term" dans l'argument de l'url.

Voici le code javascript du script que j'ai trouvé pour insérer des tags existants et nouveaux :


    $(function() {
        $('#form-tags').tagsInput({
            'autocomplete': {
                source: function (query, process) {
                    return $.get('itemp.php', {query: query}, function (data) {
                        //data = $.parseJSON(data);
                        return process(data);
                    });
                }
            }
        });
    });

    /* jQuery Tags Input Revisited Plugin */

    (function($) {
        var delimiter = [];
        var inputSettings = [];
        var callbacks = [];

        $.fn.addTag = function(value, options) {
            options = jQuery.extend({
                focus: false,
                callback: true
            }, options);

            this.each(function() {
                var id = $(this).attr('id');

                var tagslist = $(this).val().split(_getDelimiter(delimiter[id]));
                if (tagslist[0] === '') tagslist = [];

                value = jQuery.trim(value);

                if ((inputSettings[id].unique && $(this).tagExist(value)) || !_validateTag(value, inputSettings[id], tagslist, delimiter[id])) {
                    $('#' + id + '_tag').addClass('error');
                    return false;
                }

                $('<span>', {class: 'tag'}).append(
                    $('<span>', {class: 'tag-text'}).text(value),
                    $('<button>', {class: 'tag-remove'}).click(function() {
                        return $('#' + id).removeTag(encodeURI(value));
                    })
                ).insertBefore('#' + id + '_addTag');

                tagslist.push(value);

                $('#' + id + '_tag').val('');
                if (options.focus) {
                    $('#' + id + '_tag').focus();
                } else {
                    $('#' + id + '_tag').blur();
                }

                $.fn.tagsInput.updateTagsField(this, tagslist);

                if (options.callback && callbacks[id] && callbacks[id]['onAddTag']) {
                    var f = callbacks[id]['onAddTag'];
                    f.call(this, this, value);
                }

                if (callbacks[id] && callbacks[id]['onChange']) {
                    var i = tagslist.length;
                    var f = callbacks[id]['onChange'];
                    f.call(this, this, value);
                }
            });

            return false;
        };

        $.fn.removeTag = function(value) {
            value = decodeURI(value);

            this.each(function() {
                var id = $(this).attr('id');

                var old = $(this).val().split(_getDelimiter(delimiter[id]));

                $('#' + id + '_tagsinput .tag').remove();

                var str = '';
                for (i = 0; i < old.length; ++i) {
                    if (old[i] != value) {
                        str = str + _getDelimiter(delimiter[id]) + old[i];
                    }
                }

                $.fn.tagsInput.importTags(this, str);

                if (callbacks[id] && callbacks[id]['onRemoveTag']) {
                    var f = callbacks[id]['onRemoveTag'];
                    f.call(this, this, value);
                }
            });

            return false;
        };

        $.fn.tagExist = function(val) {
            var id = $(this).attr('id');
            var tagslist = $(this).val().split(_getDelimiter(delimiter[id]));
            return (jQuery.inArray(val, tagslist) >= 0);
        };

        $.fn.importTags = function(str) {
            var id = $(this).attr('id');
            $('#' + id + '_tagsinput .tag').remove();
            $.fn.tagsInput.importTags(this, str);
        };

        $.fn.tagsInput = function(options) {
            var settings = jQuery.extend({
                interactive: true,
                placeholder: 'Add a tag',
                minChars: 0,
                maxChars: null,
                limit: null,
                validationPattern: null,
                width: 'auto',
                height: 'auto',
                autocomplete: null,
                hide: true,
                delimiter: ',',
                unique: true,
                removeWithBackspace: true
            }, options);

            var uniqueIdCounter = 0;

            this.each(function() {
                if (typeof $(this).data('tagsinput-init') !== 'undefined') return;

                $(this).data('tagsinput-init', true);

                if (settings.hide) $(this).hide();

                var id = $(this).attr('id');
                if (!id || _getDelimiter(delimiter[$(this).attr('id')])) {
                    id = $(this).attr('id', 'tags' + new Date().getTime() + (++uniqueIdCounter)).attr('id');
                }

                var data = jQuery.extend({
                    pid: id,
                    real_input: '#' + id,
                    holder: '#' + id + '_tagsinput',
                    input_wrapper: '#' + id + '_addTag',
                    fake_input: '#' + id + '_tag'
                }, settings);

                delimiter[id] = data.delimiter;
                inputSettings[id] = {
                    minChars: settings.minChars,
                    maxChars: settings.maxChars,
                    limit: settings.limit,
                    validationPattern: settings.validationPattern,
                    unique: settings.unique
                };

                if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
                    callbacks[id] = [];
                    callbacks[id]['onAddTag'] = settings.onAddTag;
                    callbacks[id]['onRemoveTag'] = settings.onRemoveTag;
                    callbacks[id]['onChange'] = settings.onChange;
                }

                var markup = $('<div>', {id: id + '_tagsinput', class: 'tagsinput'}).append(
                    $('<div>', {id: id + '_addTag'}).append(
                        settings.interactive ? $('<input>', {id: id + '_tag', class: 'tag-input', value: '', placeholder: settings.placeholder}) : null
                    )
                );

                $(markup).insertAfter(this);

                $(data.holder).css('width', settings.width);
                $(data.holder).css('min-height', settings.height);
                $(data.holder).css('height', settings.height);

                if ($(data.real_input).val() !== '') {
                    $.fn.tagsInput.importTags($(data.real_input), $(data.real_input).val());
                }

                // Stop here if interactive option is not chosen
                if (!settings.interactive) return;

                $(data.fake_input).val('');
                $(data.fake_input).data('pasted', false);

                $(data.fake_input).on('focus', data, function(event) {
                    $(data.holder).addClass('focus');

                    if ($(this).val() === '') {
                        $(this).removeClass('error');
                    }
                });

                $(data.fake_input).on('blur', data, function(event) {
                    $(data.holder).removeClass('focus');
                });

                if (settings.autocomplete !== null && jQuery.ui.autocomplete !== undefined) {
                    $(data.fake_input).autocomplete(settings.autocomplete);
                    $(data.fake_input).on('autocompleteselect', data, function(event, ui) {
                        $(event.data.real_input).addTag(ui.item.value, {
                            focus: true,
                            unique: settings.unique
                        });

                        return false;
                    });

                    $(data.fake_input).on('keypress', data, function(event) {
                        if (_checkDelimiter(event)) {
                            $(this).autocomplete("close");
                        }
                    });
                } else {
                    $(data.fake_input).on('blur', data, function(event) {
                        $(event.data.real_input).addTag($(event.data.fake_input).val(), {
                            focus: true,
                            unique: settings.unique
                        });

                        return false;
                    });
                }

                // If a user types a delimiter create a new tag
                $(data.fake_input).on('keypress', data, function(event) {
                    if (_checkDelimiter(event)) {
                        event.preventDefault();

                        $(event.data.real_input).addTag($(event.data.fake_input).val(), {
                            focus: true,
                            unique: settings.unique
                        });

                        return false;
                    }
                });

                $(data.fake_input).on('paste', function () {
                    $(this).data('pasted', true);
                });

                // If a user pastes the text check if it shouldn't be splitted into tags
                $(data.fake_input).on('input', data, function(event) {
                    if (!$(this).data('pasted')) return;

                    $(this).data('pasted', false);

                    var value = $(event.data.fake_input).val();

                    value = value.replace(/\n/g, '');
                    value = value.replace(/\s/g, '');

                    var tags = _splitIntoTags(event.data.delimiter, value);

                    if (tags.length > 1) {
                        for (var i = 0; i < tags.length; ++i) {
                            $(event.data.real_input).addTag(tags[i], {
                                focus: true,
                                unique: settings.unique
                            });
                        }

                        return false;
                    }
                });

                // Deletes last tag on backspace
                data.removeWithBackspace && $(data.fake_input).on('keydown', function(event) {
                    if (event.keyCode == 8 && $(this).val() === '') {
                        event.preventDefault();
                        var lastTag = $(this).closest('.tagsinput').find('.tag:last > span').text();
                        var id = $(this).attr('id').replace(/_tag$/, '');
                        $('#' + id).removeTag(encodeURI(lastTag));
                        $(this).trigger('focus');
                    }
                });

                // Removes the error class when user changes the value of the fake input
                $(data.fake_input).keydown(function(event) {
                    // enter, alt, shift, esc, ctrl and arrows keys are ignored
                    if (jQuery.inArray(event.keyCode, [13, 37, 38, 39, 40, 27, 16, 17, 18, 225]) === -1) {
                        $(this).removeClass('error');
                    }
                });
            });

            return this;
        };

        $.fn.tagsInput.updateTagsField = function(obj, tagslist) {
            var id = $(obj).attr('id');
            $(obj).val(tagslist.join(_getDelimiter(delimiter[id])));
        };

        $.fn.tagsInput.importTags = function(obj, val) {
            $(obj).val('');

            var id = $(obj).attr('id');
            var tags = _splitIntoTags(delimiter[id], val);

            for (i = 0; i < tags.length; ++i) {
                $(obj).addTag(tags[i], {
                    focus: false,
                    callback: false
                });
            }

            if (callbacks[id] && callbacks[id]['onChange']) {
                var f = callbacks[id]['onChange'];
                f.call(obj, obj, tags);
            }
        };

        var _getDelimiter = function(delimiter) {
            if (typeof delimiter === 'undefined') {
                return delimiter;
            } else if (typeof delimiter === 'string') {
                return delimiter;
            } else {
                return delimiter[0];
            }
        };

        var _validateTag = function(value, inputSettings, tagslist, delimiter) {
            var result = true;

            if (value === '') result = false;
            if (value.length < inputSettings.minChars) result = false;
            if (inputSettings.maxChars !== null && value.length > inputSettings.maxChars) result = false;
            if (inputSettings.limit !== null && tagslist.length >= inputSettings.limit) result = false;
            if (inputSettings.validationPattern !== null && !inputSettings.validationPattern.test(value)) result = false;

            if (typeof delimiter === 'string') {
                if (value.indexOf(delimiter) > -1) result = false;
            } else {
                $.each(delimiter, function(index, _delimiter) {
                    if (value.indexOf(_delimiter) > -1) result = false;
                    return false;
                });
            }

            return result;
        };

        var _checkDelimiter = function(event) {
            var found = false;

            if (event.which === 13) {
                return true;
            }

            if (typeof event.data.delimiter === 'string') {
                if (event.which === event.data.delimiter.charCodeAt(0)) {
                    found = true;
                }
            } else {
                $.each(event.data.delimiter, function(index, delimiter) {
                    if (event.which === delimiter.charCodeAt(0)) {
                        found = true;
                    }
                });
            }

            return found;
        };

        var _splitIntoTags = function(delimiter, value) {
            if (value === '') return [];

            if (typeof delimiter === 'string') {
                return value.split(delimiter);
            } else {
                var tmpDelimiter = '?';
                var text = value;

                $.each(delimiter, function(index, _delimiter) {
                    text = text.split(_delimiter).join(tmpDelimiter);
                });

                return text.split(tmpDelimiter);
            }

            return [];
        };
    })(jQuery);


Avez-vous une idée de la raison du problème ?

Y a-t-il un moyen pour débugger facilement le code javascript / Ajax ?

Merci d'avance

Bonne journée
Thierry
Salut

Logiquement ta requête te renvoit un tableau, si tu as besoin de JSON alors tu fais json_encode() et basta Smiley smile
Bonjour Jencal,

tout d'abord, je tenais à vous remercier pour votre réponse.

En effet, je suis d'accord avec vous mais le problème est que ma page php n'est même pas appelée à cause de cette erreur :

Uncaught TypeError: Cannot use 'in' operator to search for 'length' in []
at w (jquery.min.js:2)
at Function.map (jquery.min.js:2)
at t.<computed>.<computed>._normalize (jquery-ui.min.js:8)
at t.<computed>.<computed>._normalize (jquery-ui.min.js:6)
at t.<computed>.<computed>.__response (jquery-ui.min.js:8)
at t.<computed>.<computed>.__response (jquery-ui.min.js:6)
at t.<computed>.<computed>.n (jquery-ui.min.js:6)
at t.<computed>.<computed>.__response (jquery-ui.min.js:8)
at t.<computed>.<computed>.__response (jquery-ui.min.js:6)
at t.<computed>.<computed>.<anonymous> (jquery-ui.min.js:8)

Au niveau de l'url de ma page PHP, voici comment l'appel est fait :

item.php?query%5Bterm%5D=pizza

alors que normalement, je devrais avoir l'appel suivant :

item.php?query=pizza

Voici ce que fait mon script php :


    $keysearch = $_GET['query'] . '%';

    $sql_search_items = $db->prepare("SELECT ITEM_ID as id, ITEM_VALUE as name FROM ITEMS WHERE ITEM_DATA LIKE ?");
    $sql_search_items->execute(array($keysearch));

    $userItems = array();

    $count_items = $sql_search_items->rowCount();

    if ($count_items > 0)
    {
        while ($user_items = $sql_search_items->fetch(PDO::FETCH_ASSOC))
        {
            $userItems [] = $user_items;
        }
    }

    echo json_encode($userItems );


Merci d'avance

Bonne journée
Thierry
Bonjour Jencal,

apparemment, il rentre bien dans mon code php mais je n'arrive pas à extraire la valeur du paramètre car l'argument qui est passé est bizarre :

item.php?query%5Bterm%5D=pizza

alors que, normalement, je devrais simplement avoir ceci :

item.php?query=pizza

Donc, quand j'essaie de récupérer cet argument à partir de mon code PHP, il n'arrive pas à reconnaître cette variable et le contenu est donc vide :


$keysearch = $_GET['query%5Bterm%5D'] . '%';


Donc, il me renvoie bien un tableau JSON avec toutes les valeurs :

["cake","pizza","salade"]

Par contre, il ne m'affiche pas la liste des propositions que je tape quelque chose dans le champ input alors que, dans mon cas, en tapant "piz", il devrait me proposer "pizza".

Voici l'erreur que je reçois :

Uncaught TypeError: Cannot use 'in' operator to search for 'length' in ["cake","pizza","salade"]
at w (jquery.min.js:2)
at Function.map (jquery.min.js:2)
at t.<computed>.<computed>._normalize (jquery-ui.min.js:8)
at t.<computed>.<computed>._normalize (jquery-ui.min.js:6)
at t.<computed>.<computed>.__response (jquery-ui.min.js:8)
at t.<computed>.<computed>.__response (jquery-ui.min.js:6)
at t.<computed>.<computed>.n (jquery-ui.min.js:6)
at t.<computed>.<computed>.__response (jquery-ui.min.js:8)
at t.<computed>.<computed>.__response (jquery-ui.min.js:6)
at t.<computed>.<computed>.<anonymous> (jquery-ui.min.js:8)

Merci d'avance

Bonne journée
Thierry
Bonjour à tous,

maintenant, j'ai réussi à résoudre le problème concernant le paramètre dans l'url.

En fait, il fallait renseigner la propriété "term" de la objet "query" :


        $('#form-tags-4').tagsInput({
            'autocomplete': {
                source: function (query, process) {
                    return $.get('item.php', {query: query.term}, function (data) {
                        data = $.parseJSON(data);
                        return process(data);
                    });
                }
            }
        });


Par contre, je ne comprends pas comment je dois faire pour récupérer les valeurs tapées par l'utilisateur.

De plus, comme je le disais dans mon premier mail, je ne comprends pas pourquoi le champ qui a la propriété css "display: none;" s'affiche.


        <label>Tags input with autocomplete:</label>
        <input id="form-tags-4" name="tags-4" type="text" value="" [b]style="display: none;"[/b]>
        <div id="form-tags-4_tagsinput" class="tagsinput" style="width: auto; min-height: auto; height: auto;">
            <div id="form-tags-4_addTag">
                <input id="form-tags-4_tag" class="tag-input ui-autocomplete-input" value="" placeholder="Add a tag" autocomplete="off">
            </div>
        </div>


Merci d'avance pour votre aide.

Bonne journée
Thierry