knockout.js 在Durandal Framework中使用Typeahead创建自动完成字段

xtupzzrd  于 2022-11-10  发布在  其他
关注(0)|答案(4)|浏览(156)

我正在尝试用typeahead(Twitter Bootstrap)实现一个自动完成输入字段。这个自动完成字段应该是模态的,但是我似乎不能让它工作!它还必须是可以用Knockout观察到的,因为当你选择一个值时,其他字段应该被更新到。
所以我想用一种模式来做这个!
HTML语言

<div class="messageBox">
    <div class="modal-header">
        <h2>Adding a repairline</h2>
    </div>
    <div class="modal-body" style="width: 35em;">
        <form data-bind="submit: ok">
            <fieldset>
                <!--<legend></legend> Deze niet toevoegen uitlijning is dan niet goed!-->
                <div class="row-fluid">
                    <div class="span6">
                        <div>   
                            <label>
                                Description:
                                <input type="text" id="testen" data-provide="typeahead" />

                            </label>
                        </div>
                        <div>
                            <label>
                                Code:
                                <input data-bind="value: Code" required />
                            </label>
                        </div>          
                <div>
                    <input class="btn btn-primary" type="submit" value="Add" />
                </div>
            </fieldset>
        </form>
    </div>
    <div class="modal-footer">
        <button class="btn" data-bind="click: closeModal">Cancel</button>    
    </div>
</div>

JS系统

define(function (require) {
    var dataservice = require('services/dataservice'),
        allCustomers = ko.observableArray([]),
        repairlines = ko.observableArray([]);

    function init() {
        dataservice = new dataservice('api/data');
        dataservice.getAllRows('AllCustomers').then(function (data) {
            data.results.forEach(function (item) {
                allCustomers.push(item);
            });
        }).fail(function () {   
        });

        dataservice.getAllRows('EntireRepairLineLib').then(function (data) {
            data.results.forEach(function (item) {
                repairlines.push(item);
            });
        }).fail(function () {
        });

        $('.testen .typeahead').typeahead({
            name: 'countries',
            prefetch: 'http://twitter.github.io/typeahead.js/data/countries.json',
            limit: 10
        });
    }

    init();

    AddRepairOrderLineModal = function (loggedInEmployee) {
        //later ook customer en repairorder meegeven!
        this.allCustomers = allCustomers;
        this.choosenCustomerId = ko.observable(); //holds the Id of the chosen customer
        this.Description = ko.observable();
        this.Code = ko.observable();
        this.Mat = ko.observable();
        this.Location = ko.observable();
        this.Rep = ko.observable();
        this.Dum = ko.observable();
        this.Dam = ko.observable();
        this.Qty = ko.observable();
        this.Hours = ko.observable();
        this.Tariff = ko.observable();
        this.Costs = ko.observable();
        this.CreationDate = (new Date().getMonth() + 1) + "-" + new Date().getDate() + "-" + new Date().getFullYear();

        this.IsAgreement = ko.observable(true);
        this.IsAuthorized = ko.observable(true);
        this.DoRepair = ko.observable(true);
        this.selectedEmployee = loggedInEmployee;

       /* $(".repairlinename").autocomplete({
           source: repairlines 
        });*/

        $(document).ready(function() {
            alert('done');
            $('#testen').append(' Leroy');
        }); 
    };
    AddRepairOrderLineModal.prototype.ok = function () {
        var jsonObj = [];
        jsonObj.push({
            Description: this.Description(), Code: this.Code(),
            Mat: this.Mat(), Location: this.Location(),
            Rep: this.Rep(), Dum: this.Dum(), Dam: this.Dam(),
            CustomerId: this.choosenCustomerId(), Qty: this.Qty(), Hours: this.Hours(),
            Tariff: this.Tariff(), Costs: this.Costs(), CreationDate: this.CreationDate,
            IsAgreement: this.IsAgreement(), IsAuthorized: this.IsAuthorized(), DoRepair: this.DoRepair(),
        });
        this.modal.close(jsonObj);
    };

    AddRepairOrderLineModal.prototype.closeModal = function () {
        return this.modal.close();
    };
    return AddRepairOrderLineModal;
});

    /*define(['durandal/app','services/dataservice'], function(app,dataservice) {
        AddRepairOrderLineModal = function (loggedInEmployee) {
            //later ook customer en repairorder meegeven!

            this.Description = ko.observable();
            this.Code = ko.observable();
            this.Mat = ko.observable();
            this.Location = ko.observable();
            this.Rep = ko.observable();
            this.Dum = ko.observable();
            this.Dam = ko.observable();
            this.Customer = ko.observable();
            this.Qty = ko.observable();
            this.Hours = ko.observable();
            this.Tariff = ko.observable();
            this.Costs = ko.observable();
            this.CreationDate = (new Date().getMonth() + 1) + "-" + new Date().getDate() + "-" + new Date().getFullYear();

            this.IsAgreement = ko.observable(true);
            this.IsAuthorized = ko.observable(true);
            this.DoRepair = ko.observable(true);
            this.selectedEmployee = loggedInEmployee;
        };

        AddRepairOrderLineModal.prototype.ok = function () {
            var jsonObj = [];
            jsonObj.push({
                Description: this.Description(), Code: this.Code(),
                Mat: this.Mat(), Location: this.Location(),
                Rep: this.Rep(), Dum: this.Dum(), Dam: this.Dam(),
                Customer: this.Customer(), Qty: this.Qty(), Hours: this.Hours(),
                Tariff: this.Tariff(), Costs: this.Costs(), CreationDate: this.CreationDate,
                IsAgreement: this.IsAgreement(), IsAuthorized: this.IsAuthorized(), DoRepair: this.DoRepair()
            });
            this.modal.close(jsonObj);
        };

        AddRepairOrderLineModal.prototype.closeModal = function() {
            return this.modal.close();
        };
        return AddRepairOrderLineModal;
        /*
        http://stackoverflow.com/questions/7537002/autocomplete-combobox-with-knockout-js-template-jquery
        http://jsfiddle.net/rniemeyer/PPsRC/
        *//*
    });

    */

来源是维修行,这些都已正确填写。

ykejflvf

ykejflvf1#

您需要将typeahead输入绑定到视图模型上公开的数组中,我认为您目前还没有这样做。
要进行绑定,您应该使用以下位置提供的knockout-bootstrap绑定:http://billpull.github.io/knockout-bootstrap/
一旦您包含了上面的knockout-bootstrap绑定,您就可以在视图中执行此操作:

<input type="text" data-bind="typeahead: repairlines" />

然后确保您正在将修复行添加到VM示例中。将其添加到this引用中应该可以达到此目的。

// this will add the repairlines observable array to your VM instance
this.repairlines = repairlines;
xam8gpfp

xam8gpfp2#

我想评论,但不能,所以这里是我的笔记。在你的例子中,你有一个同源政策(SOP)的问题。所以从twitter页面的数据没有被拉进来。这几乎杀死了过程,所以你没有结束任何东西。
我发现,如果包含适当的样式(例如tt-dropdown-menu的样式):

<span class="tt-dropdown-menu" style="position: absolute; top: 100%; left: 0px; z-index: 100; display: block; right: auto;"></span>

这是我尝试http://jsfiddle.net/rUdXt/的一小部分,这是一个很棒的页面,它对我很有帮助(特别是http://twitter.github.io/typeahead.js/examples/的样式)。

h5qlskok

h5qlskok3#

我已经通过向库中添加一些额外的代码修复了此问题:https://github.com/billpull/knockout-bootstrap
这是knockout-bootstrap.js,在这里ko.bindingHandlers.typeahead被重写了,所以它接受更新,minLength和en items。只需在中加载这个脚本。

//UUID
function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
}

function guid() {
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

// Outer HTML
(function($){
  $.fn.outerHtml = function() {
    if (this.length == 0) return false;
    var elem = this[0], name = elem.tagName.toLowerCase();
    if (elem.outerHTML) return elem.outerHTML;
    var attrs = $.map(elem.attributes, function(i) { return i.name+'="'+i.value+'"'; }); 
    return "<"+name+(attrs.length > 0 ? " "+attrs.join(" ") : "")+">"+elem.innerHTML+"</"+name+">";
  };
})(jQuery);

// Bind twitter typeahead
ko.bindingHandlers.typeahead = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var $element = $(element);
        var allBindings = allBindingsAccessor();
        var typeaheadArr = ko.utils.unwrapObservable(valueAccessor());

        $element.attr("autocomplete", "off")
                .typeahead({
                    'source': typeaheadArr,
                    'minLength': allBindings.minLength,
                    'items': allBindings.items,
                    'updater': allBindings.updater
                });
    }
};

/*
ko.bindingHandlers.typeahead = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

        var $element = $(element);
        var t = valueAccessor();
        var typeaheadArr = ko.utils.unwrapObservable(valueAccessor());
        var k = allBindingsAccessor().v1;

        $element.attr("autocomplete", "off")
                .typeahead({
                    'source' : typeaheadArr
                });
    }
};

* /

// Bind Twitter Progress
ko.bindingHandlers.progress = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var $element = $(element);

        var bar = $('<div/>', {
            'class':'bar',
            'data-bind':'style: { width:' + valueAccessor() + ' }'
        });

        $element.attr('id', guid())
            .addClass('progress progress-info')
            .append(bar);

        ko.applyBindingsToDescendants(viewModel, $element[0]);
    }
}

// Bind Twitter Alert
ko.bindingHandlers.alert = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var $element = $(element);
        var alertInfo = ko.utils.unwrapObservable(valueAccessor());

        var dismissBtn = $('<button/>', {
            'type':'button',
            'class':'close',
            'data-dismiss':'alert'
        }).html('&times;');

        var alertMessage = $('<p/>').html(alertInfo.message);

        $element.addClass('alert alert-'+alertInfo.priority)
                .append(dismissBtn)
                .append(alertMessage);
    }
};

// Bind Twitter Tooltip
ko.bindingHandlers.tooltip = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // read tooltip options
        var tooltipBindingValues = ko.utils.unwrapObservable(valueAccessor());

        // set tooltip title
        var tooltipTitle = tooltipBindingValues.title;

        // set tooltip placement
        var tooltipPlacement = tooltipBindingValues.placement;

        // set tooltip trigger
        var tooltipTrigger = tooltipBindingValues.trigger;

        var options = {
            title: tooltipTitle
        };

        ko.utils.extend(options, ko.bindingHandlers.tooltip.options);

        if (tooltipPlacement) {
            options.placement = tooltipPlacement;
        }

        if (tooltipTrigger) {
            options.trigger = tooltipTrigger;
        }

        $(element).tooltip(options);
    },
    options: {
        placement: "top",
        trigger: "hover"
    }
};

// Bind Twitter Popover
ko.bindingHandlers.popover = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // read popover options 
        var popoverBindingValues = ko.utils.unwrapObservable(valueAccessor());

        // set popover title 
        var popoverTitle = popoverBindingValues.title;

        // set popover template id
        var tmplId = popoverBindingValues.template;

        // set popover trigger
        var trigger = 'click';

        if (popoverBindingValues.trigger) {
            trigger = popoverBindingValues.trigger;
        }

        // update triggers
        if (trigger === 'hover') {
            trigger = 'mouseenter mouseleave';
        } else if (trigger === 'focus') {
            trigger = 'focus blur';
        }

        // set popover placement
        var placement = popoverBindingValues.placement;

        // get template html
        var tmplHtml = $('#' + tmplId).html();

        // create unique identifier to bind to
        var uuid = guid();
        var domId = "ko-bs-popover-" + uuid;

        // create correct binding context
        var childBindingContext = bindingContext.createChildContext(viewModel);

        // create DOM object to use for popover content
        var tmplDom = $('<div/>', {
            "class" : "ko-popover",
            "id" : domId
        }).html(tmplHtml);

        // set content options
        options = {
            content: $(tmplDom[0]).outerHtml(),
            title: popoverTitle
        };

        if (placement) {
            options.placement = placement;
        }

        // Need to copy this, otherwise all the popups end up with the value of the last item
        var popoverOptions = $.extend({}, ko.bindingHandlers.popover.options, options);

        // bind popover to element click
        $(element).bind(trigger, function () {
            var popoverAction = 'show';
            var popoverTriggerEl = $(this);

            // popovers that hover should be toggled on hover
            // not stay there on mouseout
            if (trigger !== 'click') {
                popoverAction = 'toggle';
            }

            // show/toggle popover
            popoverTriggerEl.popover(popoverOptions).popover(popoverAction);

            // hide other popovers and bind knockout to the popover elements
            var popoverInnerEl = $('#' + domId);
            $('.ko-popover').not(popoverInnerEl).parents('.popover').remove();

            // if the popover is visible bind the view model to our dom ID
            if($('#' + domId).is(':visible')){
                ko.applyBindingsToDescendants(childBindingContext, $('#' + domId)[0]);
            }

            // bind close button to remove popover
            $(document).on('click', '[data-dismiss="popover"]', function (e) {
                popoverTriggerEl.popover('hide');
            });
        });

        // Also tell KO *not* to bind the descendants itself, otherwise they will be bound twice
        return { controlsDescendantBindings: true };
    },
    options: {
        placement: "right",
        title: "",
        html: true,
        content: "",
        trigger: "manual"
    }
};

在HTML中执行此操作。

<input type="text" data-bind="typeahead: repairlines(), minLength: 2, updater: updateViewAfterSelection, value: Description" required/>

这是我的视图模型:

define(function (require) {
    var dataservice = require('services/dataservice'),
        allCustomers = ko.observableArray([]),
        repairlinesRaw = ko.observableArray([]),
        Description = ko.observable(),
        InternalCode = ko.observable(),
        Mat = ko.observable(),
        Location = ko.observable(),
        Rep = ko.observable(),
        Dum = ko.observable(),
        Dam = ko.observable(),
        Qty = ko.observable(0).extend({ numeric: 2 }),
        Hours = ko.observable(0).extend({ numeric: 2 }),
        Tariff = ko.observable(0).extend({ numeric: 2 }),
        Costs = ko.observable(0).extend({ numeric: 2 });

    function init() {
        dataservice = new dataservice('api/data');
        dataservice.getAllRows('AllCustomers').then(function (data) {
            data.results.forEach(function (item) {
                allCustomers.push(item);
            });
        }).fail(function () {
        });

        dataservice.getAllRows('EntireRepairLineLib').then(function (data) {
            data.results.forEach(function (item) {
                repairlinesRaw.push(item);
            });
        }).fail(function () {
        });
    }

    init();

    AddRepairOrderLineModal = function (loggedInEmployee) {
        //later ook customer en repairorder meegeven!
        this.allCustomers = allCustomers;
        this.choosenCustomerId = ko.observable(); //holds the Id of the chosen customer
        this.Description = Description;
        this.InternalCode = InternalCode;
        this.Mat = Mat;
        this.Location = Location;
        this.Rep = Rep;
        this.Dam = Dam;
        this.Qty = Qty;
        this.Hours = Hours;
        this.Tariff = Tariff;
        this.Costs = Costs;
        //this.CreationDate = (new Date().getMonth() + 1) + "-" + new Date().getDate() + "-" + new Date().getFullYear();
        this.repairlines = function () {
            var repairlinesName = [];
            map = {};
            var data = repairlinesRaw();
            $.each(data, function (i, repairline) {
                map[repairline.Description()] = repairline;
                repairlinesName.push(repairline.Description());
            });
            return repairlinesName;
        };

        this.IsAgreement = ko.observable(true);
        this.IsAuthorized = ko.observable(true);
        this.DoRepair = ko.observable(true);
        this.selectedEmployee = loggedInEmployee;
    };

    AddRepairOrderLineModal.prototype.updateViewAfterSelection = function(item) {
        //map can be found in the repairlines function
        Description(map[item].Description());
        InternalCode(map[item].InternalCode());
        Mat(map[item].MaterialCode());
        Location(map[item].LocationCode());
        Rep(map[item].RepairCode());
        Dam(map[item].DamageCode());
        Qty(map[item].Quantity());
        Hours(map[item].Hours());
        Costs(map[item].Costs());
        return item;
    };

    AddRepairOrderLineModal.prototype.ok = function () {
        var jsonObj = [];
        jsonObj.push({
            Description: this.Description(), InternalCode: this.InternalCode(),
            Mat: this.Mat(), Location: this.Location(),
            Rep: this.Rep(), Dam: this.Dam(),
            CustomerId: this.choosenCustomerId(), Qty: this.Qty(), Hours: this.Hours(),
            Tariff: this.Tariff(), Costs: this.Costs(),
            IsAgreement: this.IsAgreement(), IsAuthorized: this.IsAuthorized(), DoRepair: this.DoRepair(),
        });

        //empty all fields after JSON 
        //Otherwise the values would still be there when a new modal is opened again.
        Description(null);
        InternalCode(null);
        Mat(null);
        Location(null);
        Rep(null);
        Dum(null);
        Dam(null);
        Qty(0);
        Hours(0);
        Tariff(0);
        Costs(0);

        this.modal.close(jsonObj);
    };

    AddRepairOrderLineModal.prototype.closeModal = function () {
        return this.modal.close();
    };
    return AddRepairOrderLineModal;
});

很多功劳都要归功于比尔·拉和亚历克斯·普雷斯顿。

41ik7eoe

41ik7eoe4#

无法理解,因为它太混乱了。也就是说,typeahead位和你所有其他的东西混在一起了。一个简单的例子怎么样,它只有typeahead的东西,也许是像一个小部件一样组成一个视图/视图模型,这样它就可以重用了。
这样我们就有机会了解它

相关问题