Как сохранить синхронизирующий синхронный синхронизирующий эффект knockout.js

117
14

У меня есть 3 наблюдаемых нокаута, которые взаимосвязаны между собой. Они есть

retail_price, selling_price, скидка

Когда пользователь меняет одно значение, другие другие наблюдаемые обновляются. Например,

    Если пользователь вводит отпускную цену до 1000, розничная цена устанавливается равной 1000, а скидка - 0. Следуя приведенному выше примеру, теперь, если пользователь переходит и редактирует retail_price как 2000, скидка обновляется до 50.

Теперь все это отлично работает, если у меня нет события afterkeydown. Поэтому, когда пользователь вводит какое-либо значение и переходит к следующему полю, это нормально.

Проблема заключается в том, что, когда я сохраняю afterkeydown, как только я начинаю печатать, на основе первого символа вычисляются другие значения. Теперь, когда я ввожу второе целое число, значения перепутаны.

Например,

sales_price = 10, retail_price = 1, discount = -900

Я не могу найти решение для этого. Какие-либо предложения?

С Уважением,

Обновить

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

    Начните с розничной продажи: продается в розницу и скидка = 0 Начните с продажи: Retails получает задание как продажа и скидки = 0 Начните с скидки. Можно добавить либо розничную, либо следующую продажу.

Пользователь может вводить значения в любом порядке.

http://jsfiddle.net/EcD3d/5/

Html:

<code>

<div>retail_price:
<input type="text" data-bind="value: retail_price.formatted, hasfocus: retail_price.isFocused, valueUpdate: 'afterkeydown'" />
</div>
<div>selling_price:
<input type="text" data-bind="value: selling_price.formatted, hasfocus: selling_price.isFocused, valueUpdate: 'afterkeydown'" />
</div>
<div>discount:
<input type="text" data-bind="value: discount, hasfocus: discount.isFocused, valueUpdate: 'afterkeydown'" />
</div>

</code>

Javascript:

 function hasOwnProperty(obj, prop) { var proto = obj.__proto__ || obj.constructor.prototype; return (prop in obj) && (!(prop in proto) || proto[prop] !== obj[prop]); } function roundNumber(value, precision, flt) { var precision = precision || 0, neg = value < 0, power = Math.pow(10, precision), value = Math.round(value * power), integral = String((neg? Math.ceil: Math.floor)(value/power)), fraction = String((neg? -value: value) % power), padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0'); if (flt === true) { integral = parseFloat(integral); } return precision? integral + '.' + padding + fraction: integral; } var util = {}; util.format = function (value, prefix) { var pr = prefix || ''; toks = roundNumber(value, 2).replace('-', '').split('.'); var display = pr + $.map(toks[0].split('').reverse(), function (elm, i) { return [(i % 3 === 0 && я > 0? ',': ''), elm]; }).reverse().join('') + '.' + toks[1]; return value < 0? '-' + display: display; }; ko.subscribable.fn.formatted = function (options) { var target = this; var _options = (options === undefined)? {}: options; var _prefix = hasOwnProperty(_options, 'prefix')? _options.prefix: ''; var _precision = hasOwnProperty(_options, 'precision')? _options.precision: 2; var _type = hasOwnProperty(_options, 'type')? _options.type: 2; var format = function (value) { switch (_type) { case 1: return util.format(roundNumber(value, _precision), _prefix);//currency w/symbol case 2: return roundNumber(value, _precision);//reg float default: throw new Error('illegal type'); } }; var focused = ko.observable(false); var writeTarget = function (value) { var stripped = value; if (isNaN(value)) { stripped = String(value).replace(/[^0-9.-]/g, ''); }//target(parseFloat(stripped)); value = parseFloat(stripped); focused()? target(!isFinite(value)? 0: value): target(!isFinite(value)? 0: roundNumber(value, _precision));//Write to underlying storage }; var result = ko.computed({ read: function() { return target(); }, write: writeTarget }); result.formatted = ko.computed({ read: function() { if (focused()) { return (isNaN(target())? '': target());//Write to underlying storage } return format(target()); }, write: writeTarget }); result.isNegative = ko.computed(function() { return target() < 0; }); result.isFocused = ko.computed({ read: function() { return focused(); }, write: function (value) { focused(value); } }); return result; }; var ViewModel = function() { var self = this; self.retail_price = ko.observable(0).extend({ throttle: 100 }).formatted({ type: 1 }); self.selling_price = ko.observable(0).extend({ throttle: 100 }).formatted({ type: 1 }); self.discount = ko.observable(0);//Whenever the retail price changes, change the selling price for jewelry self.retail_price.subscribe(function() { if (parseFloat(self.selling_price()) !== 0) { self.updateDiscount(); return; } if (self.retail_price.isFocused()) { self.changeSellingPrice(); } });//Whenever the discount changes, change the selling price self.discount.subscribe(function() { self.changeSellingPrice(); }); self.selling_price.subscribe(function (v) { if (self.selling_price.isFocused()) { if (parseFloat(self.retail_price()) !== 0) { self.updateDiscount(); return; } var retPrice = (v * 100)/(100 - self.discount()); self.retail_price(isNaN(retPrice)? 0: roundNumber(retPrice, 2)); } }); self.updateDiscount = function() { var retPr = parseFloat(self.retail_price()); var askPr = parseFloat(self.selling_price()); var discount = 100 * (retPr - askPr)/retPr; self.discount(!isFinite(discount)? 0: roundNumber(discount, 2)); }; self.changeSellingPrice = function() { var sellingPrice = self.retail_price() - (self.retail_price() * self.discount())/100; self.selling_price(isNaN(sellingPrice)? 0: roundNumber(sellingPrice, 2)); }; }; ko.applyBindings(new ViewModel());

спросил(а) 2021-01-25T20:19:54+03:00 4 месяца, 3 недели назад
1
Решение
88

Ну, значение не обновляется, потому что у вас есть проверка, что значение должно быть больше 0 (ноль), и только он будет обновлять значение. Теперь, когда вы используете привязку после привязки, после нажатия одной цифры она обновляет значение до этого, поскольку изначально оно было 0 (ноль), после чего оно перестало работать, поскольку значение не равно нулю.

Я предполагаю, что в таком случае вам нужно удалить привязку valueupdate, а также удалить проверку для isfocused. Я внес некоторые изменения. Пожалуйста, пройдите через это и дайте мне знать, если вам все еще нужны какие-либо проблемы:

http://jsfiddle.net/mLKEb/

Html:

<div>retail_price:
<input type="text" data-bind="value: retail_price.formatted, hasfocus: retail_price.isFocused" />
</div>
<div>selling_price:
<input type="text" data-bind="value: selling_price.formatted, hasfocus: selling_price.isFocused" />
</div>
<div>discount:
<input type="text" data-bind="value: discount, hasfocus: discount.isFocused" />
</div>

Javascript:

function hasOwnProperty(obj, prop) {
var proto = obj.__proto__ || obj.constructor.prototype;
return (prop in obj) && (!(prop in proto) || proto[prop] !== obj[prop]);
}

function roundNumber(value, precision, flt) {
var precision = precision || 0,
neg = value < 0,
power = Math.pow(10, precision),
value = Math.round(value * power),
integral = String((neg ? Math.ceil : Math.floor)(value / power)),
fraction = String((neg ? -value : value) % power),
padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');

if (flt === true) {
integral = parseFloat(integral);
}
return precision ? integral + '.' + padding + fraction : integral;
}

var util = {};
util.format = function (value, prefix) {
var pr = prefix || '';
toks = roundNumber(value, 2).replace('-', '').split('.');
var display = pr + $.map(toks[0].split('').reverse(), function (elm, i) {
return [(i % 3 === 0 && i > 0 ? ',' : ''), elm];
}).reverse().join('') + '.' + toks[1];

return value < 0 ? '-' + display : display;
};
ko.subscribable.fn.formatted = function (options) {
var target = this;
var _options = (options === undefined) ? {} : options;
var _prefix = hasOwnProperty(_options, 'prefix') ? _options.prefix : '';
var _precision = hasOwnProperty(_options, 'precision') ? _options.precision : 2;
var _type = hasOwnProperty(_options, 'type') ? _options.type : 2;

var format = function (value) {
switch (_type) {
case 1:
return util.format(roundNumber(value, _precision), _prefix); //currency w/ symbol
case 2:
return roundNumber(value, _precision); //reg float
default:
throw new Error('illegal type');
}
};

var focused = ko.observable(false);

var writeTarget = function (value) {
var stripped = value;
if (isNaN(value)) {
stripped = String(value).replace(/[^0-9.-]/g, '');
}

//target(parseFloat(stripped));
value = parseFloat(stripped);
focused() ? target(!isFinite(value) ? 0 : value) : target(!isFinite(value) ? 0 : roundNumber(value, _precision)); // Write to underlying storage
};

var result = ko.computed({
read: function () {
return target();
},
write: writeTarget
});

result.formatted = ko.computed({
read: function () {
if (focused()) {
return (isNaN(target()) ? '' : target()); // Write to underlying storage
}
return format(target());
},
write: writeTarget
});

result.isNegative = ko.computed(function () {
return target() < 0;
});

result.isFocused = ko.computed({
read: function () {
return focused();
},
write: function (value) {
focused(value);
}
});

return result;
};

var ViewModel = function () {
var self = this;

self.retail_price = ko.observable(0).extend({
throttle: 100
}).formatted({
type: 1
});
self.selling_price = ko.observable(0).extend({
throttle: 100
}).formatted({
type: 1
});
self.discount = ko.observable(0);

// Whenever the retail price changes, change the selling price for jewelry
self.retail_price.subscribe(function () {
if (parseFloat(self.selling_price()) !== 0) {
self.updateDiscount();
return;
}

if (self.retail_price.isFocused()) {
self.changeSellingPrice();
}

});

// Whenever the discount changes, change the selling price
self.discount.subscribe(function () {
self.changeSellingPrice();
});

self.selling_price.subscribe(function (v) {
var retPrice = (v * 100) / (100 - self.discount());
self.retail_price(isNaN(retPrice) ? 0 : roundNumber(retPrice, 2));
if (parseFloat(self.retail_price()) !== 0) {
self.updateDiscount();
}
});

self.updateDiscount = function () {

var retPr = parseFloat(self.retail_price());
var askPr = parseFloat(self.selling_price());
var discount = 100 * (retPr - askPr) / retPr;
self.discount(!isFinite(discount) ? 0 : roundNumber(discount, 2));

};

self.changeSellingPrice = function () {
var sellingPrice = self.retail_price() - (self.retail_price() * self.discount()) / 100;
self.selling_price(isNaN(sellingPrice) ? 0 : roundNumber(sellingPrice, 2));
};

};

ko.applyBindings(new ViewModel());

ответил(а) 2021-01-25T20:19:54+03:00 4 месяца, 3 недели назад
45

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

var discount = ko.computed(function() {
var discount;

// your calculation goes here
// discount = retail_price() - selling_price() …

return discount > 0 ? discount : 0;
});

ответил(а) 2021-01-25T20:19:54+03:00 4 месяца, 3 недели назад
45

Я добавил еще один наблюдаемый для отслеживания, если пользователь ввел определенное значение. Напр. наблюдаемый, если пользователь ввел розничную стоимость.

Не уверен, правильно это или нет, но, похоже, работает.

ответил(а) 2021-01-25T20:19:54+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема