4

客观的:

基于此处找到的示例。getData()使用 ajax 调用在函数中解析的数据填充相关下拉列表。目前,我的示例正在处理ajax-mocks.js文件中的静态数据,但我无法理解如何将数据正确解析到下拉列表中,以及如何像之前使用示例 mockjax 数据调用那样填充其他下拉列表。

资源:

jQuery级联下拉菜单

KnockoutJS - 加载/保存 Json 数据

jQuery Mockjax

选择2

函数.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

一些模拟ajax调用的mockjax数据

// 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));
    }
});

管理员-Ajax.php

从 admin-ajax.php 收到的响应

在此处输入图像描述

额外说明

我一直在试图弄清楚如何用来自服务器的 ajax 调用替换 Mockjax 调用,但我还没有完全理解所有使用的技术。

真诚地感谢你,感谢那些花时间帮助我引导我走向正确方向的人。在这一点上,非常感谢您的帮助。

4

1 回答 1

3

您的问题包含 PHP、jQuery、knout 和许多代码行的混合。我冒昧地提取了一个核心问题,并为这部分问题写了一个答案。

如何使用敲除创建基于异步数据的嵌套下拉列表

抽象的需求

(我认为)您的系统的工作方式是:

  • 从服务器加载集合 A 和集合 D
  • 需要从集合 A 中进行选择以从服务器检索集合 B,
  • 需要从集合 B 中进行选择以从服务器检索集合 C,
  • 当在集合 A、BC 中进行选择时,过滤 D 的列表

淘汰赛功能

在淘汰赛中,您可以使用三个功能创建此依赖链:

  • observableArray存储每个集合的服务器响应
  • subscribe选择更改后触发新请求
  • pureComputed根据多个数据源和选择自动过滤对象列表

流量顺序

在下面的示例中,我展示了如何以典型的淘汰模式实现这一点:

  1. 加载institutionscolours异步。
  2. 加载时institutions,淘汰赛将它们呈现在<select>
  3. 选定的值绑定到selection.institution
  4. faculties当这个值改变时,异步加载
  5. 做同样的加载levels
  6. 选择a 时level,过滤colours匹配所有三个

淘汰赛的依赖管理的美妙之处在于,您可以随时更新这些列表中的任何一个,并且 UI 将正确呈现。例如,您可以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>

于 2017-08-11T12:13:47.477 回答