javascript — динамический каскадный выпадающий с использованием AJAX

Задача:

На основании найденного примера Вот. Заполнение зависимых раскрывающихся списков данными, проанализированными в getData() функция с использованием вызовов AJAX. В настоящее время мой пример работает со статическими данными, найденными в ajax-mocks.js файл, но я не могу понять, как правильно проанализировать данные в раскрывающихся списках, а также заполнить другие раскрывающиеся списки, как это было ранее с примерами вызовов вызовов mockjax.

Ресурсы:

JQuery Cascading Dropdown

KnockoutJS — загрузка / сохранение данных Json

jQuery Mockjax

выбор2

functions.php

Визуализирует HTML на странице внешнего продукта woocommerce

function add_custom_toga_fields() {
if( has_term('toga', 'product_cat' ) ) {
?>
<p class="label-description"><span>1. Details</span></p>
<table id="graduation" class="custom-fields .bs-docs-example" cellspacing="0">
<tbody>
<tr>
<td class="label"><label for="institution">Institution<span class="required">*</span></label></td>
<td class="value">
<select name="institution" id="institution" class="step1 select2">
<option value="">Select institution</option>
</select>
</td>
</tr>
<tr>
<td class="label"><label for="level">Level of Award<span class="required">*</span></label></td>
<td class="value">
<select name="level" id="level" class="step2 select2">
<option value="">Select level</option>
</select>
</td>
</tr>
<tr>
<td class="label"><label for="faculty">Faculty<span class="required">*</span></label></td>
<td class="value">
<select name="faculty" id="faculty" class="step3 select2">
<option value="">Select Faculty</option>
</select>
</td>
</tr>
<tr>
<td class="label"><label for="ceremony-date">Ceremony Date<span class="required">*</span></label></td>
<td class="value">
<input name="ceremony" type="text" id="ceremony">
</td>
</tr>
<tr>
<td>
<h4>Matches <img src="<?php echo get_stylesheet_directory_uri(); ?>/assets/icons/ajax-loader.gif" data-bind="visible: loading" /></h4>
<ul class="colour-results-list" data-bind="foreach: colours, visible: colours().length > 0">
<li style="background: red;">
<span class="colour-hat" data-bind="text: colour" style="background: yellow;"></span>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<?php
}
}
add_action( 'woocommerce_before_variations_form', 'add_custom_toga_fields' );

Класс-система public.php

Получить данные из базы данных и обработать их в правильном формате

public function get_data() {
global $wpdb;

$result = array();

$records = $wpdb->get_results("CALL get_json_data");
foreach($records as $record) {
$obj = new stdClass();
$obj->institution = $record->universityid;
$obj->level = $record->levelid;
$obj->faculty = [];

$faculties = $wpdb->get_results("CALL get_courses_and_colour_by_university_and_level($obj->institution, $obj->level)");
foreach($faculties as $faculty) {
$facObj->name = $faculty->name;
array_push($obj->faculty, $facObj->name);
}
array_push($result, $obj);
}
echo json_encode($result);

wp_die();
}

таможенно-dropdown.js

Создает зависимый каскадный выпадающий

jQuery(document).ready(function() {
// Apply Select 2
jQuery(".select2").select2();

function getInstitutions() {
var results = [
{ label: 'Test 1', value: 1 },
{ label: 'Test 2', value: 2 },
{ label: 'Test 3', value: 3 },
]
return results;
}

function viewmodel() {
this.colours = ko.observableArray([]);
this.loading = ko.observable(false);
}

var graduation = new viewmodel();

ko.applyBindings(graduation, document.getElementById('graduation'));

jQuery('#graduation').cascadingDropdown({
selectBoxes: [
{
selector: '.step1',
source: getInstitutions()
},
{
selector: '.step2',
requires: ['.step1'],
source: function(request, response) {
jQuery.getJSON('/api/levels', request, function(data) {
var selectOnlyOption = data.length <= 1;
response(jQuery.map(data, function(item, index) {
return {
label: item,
value: item,
selected: selectOnlyOption
};
}));
});
}
},
{
selector: '.step3',
requires: ['.step1', '.step2'],
requireAll: true,
source: function(request, response) {
jQuery.getJSON('/api/faculties', request, function(data) {
response(jQuery.map(data, function(item, index) {
return {
label: item,
value: item,
selected: index == 0
};
}));
});
},
onChange: function(event, value, requiredValues, requirementsMet) {
if(!requirementsMet) return;

graduation.loading(true);

var ajaxData = requiredValues;
ajaxData[this.el.attr('name')] = value;
jQuery.getJSON('/api/colours', ajaxData, function(data) {
graduation.colours(data);
graduation.loading(false);
});
}
}
]
});
});

Ajax-mock.js

Некоторые данные mockjax для имитации вызова ajax

// Some mockjax code to simulate Ajax calls
var colourList = [
{
faculty: [8, 16],
institution: 2,
level: "Bachelors",
colour: 'Red'
},
{
faculty: [32, 64],
institution: 3,
level: "Doctorate",
colour: 'Green'
},
{
institution: 2,
level: "Bachelors",
faculty: [8],
colour: 'Blue'
},
{
faculty: [16],
institution: 3,
level: "Masters",
colour: 'Purple'
},
{
faculty: [16],
institution: 3,
level: "Masters",
colour: 'Pink'
},
{
faculty: [16, 32],
institution: 1,
level: "Masters",
colour: 'Brown'
},
{
level: 2,
faculty: ["Msc Business Information System Management"],
institution: 3,
colour: 'Gray'
}
];

getData();
function getData() {
var data = { 'action': 'get_data' };
var deferred = new jQuery.Deferred();

return jQuery.post(ajaxurl, data, function(response) {
var obj = JSON.parse(response);
results = obj;
}).done(function() {
return deferred.resolve(results);
}).fail(function() {
});
}

function arrayIntersect(a, b) {
return jQuery.grep(a, function(i) {
return jQuery.inArray(i, b) > -1;
});
}

function arrayToInt(array) {
var output = [];

for(var i=0;i<array.length;i++) {
if(array[i] && !isNaN(+array[i])) output.push(+array[i]);
}

return output;
}

function arrayToFloat(array) {
var output = [];

for(var i=0;i<array.length;i++) {
if(array[i] && !isNaN(parseFloat(array[i]))) output.push(parseFloat(array[i]));
}

return output;
}

function getColours(institution, level, faculty) {
var _institution = arrayToFloat([].concat(institution)),
_level = arrayToInt([].concat(level)),
_faculty = arrayToInt([].concat(faculty));

return jQuery.grep(colourList, function(item, index) {
var i = true, l = true, f = true;

if(_institution.length) {
i = jQuery.inArray(item.institution, _institution) > -1;
}

if(_level.length) {
l = jQuery.inArray(item.level, _level) > -1;
}

if(_faculty.length) {
f = arrayIntersect(item.faculty, _faculty).length > 0;
}

return !!(i && l && f);
});
}

function getLevels(level, faculty) {
var colours = getColours(null, level, faculty);

var institutions = jQuery.map(colours, function(colour) { return colour.institution; });
institutions.sort(asc);
return arrayUnique(institutions);
}

function getUniversities(institution, faculty) {
var colours = getColours(institution, null, faculty);

var levels = jQuery.map(colours, function(colour) { return colour.level; });

levels.sort(asc);
return arrayUnique(levels);
}

function getFaculties(institution, level) {
var colours = getColours(institution, level, null);

var faculties = [];
jQuery.each(colours, function(index, item) {
faculties = arrayUnique(faculties.concat(item.faculty));
});
faculties.sort(asc);
return faculties;
}

function arrayUnique(array) {
var a = array.concat();
for(var i=0; i<a.length; ++i) {
for(var j=i+1; j<a.length; ++j) {
if(a[i] === a[j])
a.splice(j--, 1);
}
}

return a;
}

function asc(a, b) {
return a - b;
}

jQuery.mockjax({
url: ajaxurl,
contentType: 'application/json; charset=utf-8',
responseTime: 1000,
response: function(settings) {
this.responseText = JSON.stringify(getLevels(settings.data.level, settings.data.faculty));
}
});

jQuery.mockjax({
url: '/api/levels',
contentType: 'application/json; charset=utf-8',
responseTime: 1000,
response: function(settings) {
this.responseText = JSON.stringify(getUniversities(settings.data.institution, settings.data.faculty));
}
});

jQuery.mockjax({
url: '/api/faculties',
contentType: 'application/json; charset=utf-8',
responseTime: 1000,
response: function(settings) {
this.responseText = JSON.stringify(getFaculties(settings.data.institution, settings.data.level));
}
});

jQuery.mockjax({
url: '/api/colours',
contentType: 'application/json; charset=utf-8',
responseTime: 1000,
response: function(settings){
this.responseText = JSON.stringify(getColours(settings.data.institution, settings.data.level, settings.data.faculty));
}
});

Admin-ajax.php

Ответ получен от admin-ajax.php

введите описание изображения здесь

Дополнительные заметки

Я застрял на некоторое время, пытаясь понять, как я могу заменить вызовы Mockjax на вызовы ajax с сервера, но мне не удалось понять все технологии, используемые в полной мере.

Искренне благодарю вас, кто бы не нашел время, чтобы помочь мне направить меня в правильном направлении. Ваша помощь очень ценится на этом этапе.

4

Решение

Ваш вопрос содержит смесь PHP, JQuery, нокаут и много строки кода. Я взял на себя смелость извлечь одну из основных проблем и написать ответ на эту часть вопроса.

Как использовать нокаут для создания вложенного списка выпадающих на основе асинхронных данных

Абстрагированные требования

Я думаю, что ваша система работает так:

  • загрузить набор A и набор D с сервера
  • запрашивать выбор из набора A для получения набора B с сервера,
  • запрашивать выбор из набора B для получения набора C с сервера,
  • когда выбор в наборе A, B а также C, отфильтровать список D

Особенности нокаута

В нокауте вы можете создать эту цепочку зависимостей, используя три функции:

  • observableArray хранить ответы сервера для каждого набора
  • subscribe инициировать новый запрос после изменения выбора
  • pureComputed автоматически фильтровать список объектов на основе нескольких источников данных & выборы

Порядок потока

В приведенном ниже примере я покажу, как реализовать это в типичной схеме выбивания:

  1. нагрузка institutions а также colours асинхронный.
  2. когда institutions нагрузка, нокаут делает их в <select>
  3. Выбранное значение привязано к selection.institution
  4. Когда это значение изменяется, загрузить faculties асинхронной
  5. Сделайте то же самое, чтобы загрузить levels
  6. Когда level выбран, фильтр colours которые соответствуют всем трем

Прелесть управления зависимостями нокаута заключается в том, что вы можете обновить любой из этих списков в любое время, и пользовательский интерфейс будет отображаться правильно. Например. Вы можете обновить свой colours Источник после того, как вы уже сделали три выбора, и список обновится.

Пример

Обратите внимание, что я использовал некоторые случайные данные из вашего фрагмента, поэтому для многих комбинаций colours имеется в наличии. Кроме того, пример содержит функции es6, которые вам может понадобиться для старых браузеров.

const App = function() {

// The data sources
this.institutions = ko.observableArray([]);
this.faculties = ko.observableArray([]);
this.levels = ko.observableArray([]);
const colours = ko.observableArray([]);

// The selections made in the UI
this.selected = {
institution: ko.observable(null),
faculty: ko.observable(null),
level: ko.observable(null)
};

// The filter logic
this.availableColours = ko.pureComputed(() => {
if (colours().length === 0 ||
this.selected.institution() === null ||
this.selected.faculty() === null ||
this.selected.level() === null) {
return [];
}

const inst = this.selected.institution();
const fac = this.selected.faculty();
const lvl = this.selected.level();

return colours()
.filter(c =>
c.institution === inst &&
c.faculty.includes(fac) &&
c.level === lvl
);
}).extend({"deferred": true});

// Loading the data:
// 1. always load institutions & colours
mockAsync(getInstitutions)
.then(this.institutions);

mockAsync(getColours)
.then(colours);

// 2. load faculties after instution
this.selected.institution.subscribe(
selection => {
this.faculties([]);
/* do something with inst. in get URL */
mockAsync(getFaculties)
.then(this.faculties)
}
);

// 3. load levels after faculty
this.selected.faculty.subscribe(
selection => {
this.levels([]);
/* do something with inst. in get URL */
mockAsync(getLevels)
.then(this.levels)
}
);
}

ko.applyBindings(new App());function mockAsync(fn) {
let _cb = () => {};
setTimeout(() => _cb(fn()), 200 + Math.random() * 300);
return {
then: cb => _cb = cb
}
};

function getLevels() { return ["Doctorate", "Bachelors", "Masters"]; };
function getInstitutions() { return [1, 2, 3]; };
function getFaculties(){ return  [8, 16, 32, 64]; };
function getColours() { return  [{faculty:[8,16],institution:2,level:"Bachelors",colour:"Red"},{faculty:[32,64],institution:3,level:"Doctorate",colour:"Green"},{institution:2,level:"Bachelors",faculty:[8],colour:"Blue"},{faculty:[16],institution:3,level:"Masters",colour:"Purple"},{faculty:[16],institution:3,level:"Masters",colour:"Pink"},{faculty:[16,32],institution:1,level:"Masters",colour:"Brown"},{level:2,faculty:["Msc Business Information System Management"],institution:3,colour:"Gray"}]; };
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<select data-bind="options: institutions,
optionsCaption: 'Select an institution',
value: selected.institution"></select>

<select data-bind="options: faculties,
optionsCaption: 'Select a faculty',
value: selected.faculty,
disable: !selected.institution()"></select>

<select data-bind="options: levels,
optionsCaption: 'Select a level',
value: selected.level,
disable: !selected.faculty()"></select>

<h3>Available colours:</h3>
<ul data-bind="foreach: availableColours">
<li data-bind="text: colour"></li>
</ul>
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]