我尝试构建项目的表单,我可以在其中放置不同的公式来计算某些字段。
主要问题:我想让公式双向工作,例如
price
时,表单应根据sum
(price
* price
)计算qty
。 sum
时,表单应根据price
(sum
/ sum
)计算项qty
。我找到了Calcx -- great and powerful jQuery plugin for building a calculation form并根据我的需要修改了其中一个例子,但没想到有可能以某种方式让它像我上面的描述那样工作。
还有一些其他问题我找不到解决方案:
readonly: false
的字段应该是可编辑的。我的示例中包含类.sum
的字段仍然不可编辑。为什么?+
- 字段周围添加了-
和qty
按钮到incr / decr功能,但为了让它们正常工作,我必须分离Calcx功能并再次附加。是否有更简单的方法来实现这一目标? 免责声明我的问题的解决方案也可能涉及除Calcx之外的其他技术。也许某些插件或框架有更好的工具满足我的需求。
对于历史记录,我也在这里添加代码示例,但要使用它可能更适合查看JSfiddle
<!DOCTYPE html>
<html>
<head>
<title>testc calcx</title>
<meta charset=utf-8>
<meta name=description content="testime">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/jquery-calx-1.1.9.js"></script>
<style type="text/css">
.plusminus {
font-weight: bold;
font-family: monospace;
font-size: 1.3em;
border: 1px green solid;
padding: 0px 5px;
}
</style>
<script>
$(document).ready(function(){
$('#itemlist').calx();
$('.sum').calx({
readonly: false
});
$('.plusminus').click(
function () {
$('#itemlist').calx('detach');
var operation = $( this ).text();
var row = $( this ).attr('id').split('_').slice(1);
var qty = $( '#qty_' + row ).val();
if ( operation == '+' ) {
$( '#qty_' + row ).val( ++qty );
} else if ( operation == '-' ) {
$( '#qty_' + row ).val( --qty );
} else {
alert( "Something wrong! " + $( this ).attr('id') );
}
$('#itemlist').calx();
$('#itemlist').calx('refresh');
}
);
});
</script>
</head>
<body>
<form id="itemlist">
<input type="text" placeholder="Item" id="A1" size="20" value="HDD Baracuda Black 2TB" />
<span id="min_1" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="qty_1" value="1" size="2" data-format="0" />
<span id="plus_1" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="C1" size="5" data-format="$ 0,0[.]00" />
<input type="text" placeholder="Disc." id="D1" size="3" data-format="0[.]00 %" />
<input type="text" placeholder="Sum" id="E1" size="6" class="sum" data-formula="($qty_1*$C1)*(1-$D1)" data-format="$ 0,0[.]00" />
<br />
<input type="text" placeholder="Item" id="A2" size="20" value="Motherboard ASus XYZ" />
<span id="min_2" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="qty_2" value="1" size="2" data-format="0" />
<span id="plus_2" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="C2" size="5" data-format="$ 0,0[.]00" />
<input type="text" placeholder="Disc." id="D2" size="3" data-format="0[.]00 %" />
<input type="text" placeholder="Sum" id="E2" size="6" class="sum" data-formula="($qty_2*$C2)*(1-$D2)" data-format="$ 0,0[.]00" />
<br />
<input type="text" placeholder="Item" id="A3" size="20" value="Memory Kingston DDR3 4GB" />
<span id="min_3" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="qty_3" value="1" size="2" data-format="0" />
<span id="plus_3" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="C3" size="5" data-format="$ 0,0[.]00" />
<input type="text" placeholder="Disc." id="D3" size="3" data-format="0[.]00 %" />
<input type="text" placeholder="Sum" id="E3" size="6" class="sum" data-formula="($qty_3*$C3)*(1-$D3)" data-format="$ 0,0[.]00" />
<br />
<input type="text" placeholder="" id="total_1" data-formula="SUM($E1,$E3)" data-format="$ 0,0[.]00" />
</form>
</body>
</html>
答案 0 :(得分:8)
我建议你使用库ractive.js。看看它的双向数据绑定是多么简单和自动:http://learn.ractivejs.org/two-way-binding/1/
<label>Enter your name: <input value='{{name}}'></label>
<p>Hello, {{name}}!</p>
所以你可以这样做:
<label>Price: <input value='{{price}}'></label>
<label>Quantity: <input value='{{quantity}}'></label>
<label>Sum: <input value='{{price * quantity}}'></label>
通过这种简单的方式,您可以使用{{price * quantity}}等表达式并保存大量代码。 http://learn.ractivejs.org/expressions/2/
您可以在{{}}和事件之间添加js函数:
http://learn.ractivejs.org/event-proxies/1/
您可以在60秒内了解如何设置ractive:http://www.ractivejs.org/60-second-setup
在其交互式教程中轻松学习:http://learn.ractivejs.org/hello-world/1/
编辑1:
我添加了此jsfiddle作为示例。
答案 1 :(得分:1)
我不喜欢图书馆,特别是如果我可以避免它们。你可以在这里清楚地避免它们。
我基本上把每个项目的所有数据都放在了自制的
中<row></row>
有了这个,我可以使用
$(this).parent();
在每个输入上,我立即拥有所需的行。从那里我将找到其他价值观。
$(document).ready(function(){
function calcTotal(){
var items = $("#itemlist row").length;
var sums = $(".sum");
var total = 0
for(var i = 0; i < items; i++){
if(sums.eq(i).val()){
total += parseFloat(sums.eq(i).val());
}
}
$("#total").val(parseFloat(total).toFixed(2));
}
function calcSum(object){
var row = $(object).parent();
var qty = row.find(".qty");
var prc = row.find(".prc");
var sum = row.find(".sum");
var disc = row.find(".disc");
var newSum = qty.val()*prc.val()*(1-disc.val()/100);
sum.val(parseFloat(newSum).toFixed(2));
calcTotal();
}
function calcPrice(object){
var row = $(object).parent();
var qty = row.find(".qty");
var prc = row.find(".prc");
var sum = row.find(".sum");
var disc = row.find(".disc");
var newPrice = -100*sum.val()/(disc.val()-100)/qty.val();
prc.val(parseFloat(newPrice).toFixed(2));
calcTotal();
}
$('.plusminus').click(function(){
var operator = parseFloat($(this).text()+"1");
var row = $(this).parent();
var qty = row.find(".qty");
var qtyVal = parseFloat(qty.val());
qty.val(parseFloat(qtyVal+operator));
calcSum(this);
});
$(".prc, .disc, .qty").blur(function(){
calcSum(this);
});
$(".sum").blur(function(){
calcPrice(this);
});
});
<body>
<form id="itemlist">
<row>
<input type="text" placeholder="Item" class="name" size="20" value="HDD Baracuda Black 2TB" />
<span id="min_1" class="plusminus">-</span>
<input type="text" placeholder="Qty" class="qty" value="1" size="2"/>
<span id="plus_1" class="plusminus" >+</span>
<input type="text" placeholder="Price" class="prc" size="5"/>
<input type="text" placeholder="Disc." class="disc" size="3"/>
<input type="text" placeholder="Sum" class="sum" size="6"/>
</row>
<row>
<input type="text" placeholder="Item" class="name" size="20" value="Motherboard ASus XYZ" />
<span id="min_1" class="plusminus">-</span>
<input type="text" placeholder="Qty" class="qty" value="1" size="2"/>
<span id="plus_1" class="plusminus" >+</span>
<input type="text" placeholder="Price" class="prc" size="5"/>
<input type="text" placeholder="Disc." class="disc" size="3"/>
<input type="text" placeholder="Sum" class="sum" size="6"/>
</row>
<row>
<input type="text" placeholder="Item" class="name" size="20" value="Memory Kingston DDR3 4GB" />
<span id="min_1" class="plusminus">-</span>
<input type="text" placeholder="Qty" class="qty" value="1" size="2"/>
<span id="plus_1" class="plusminus">+</span>
<input type="text" placeholder="Price" class="prc" size="5"/>
<input type="text" placeholder="Disc." class="disc" size="3"/>
<input type="text" placeholder="Sum" class="sum" size="6"/>
</row>
<input type="text" placeholder="Total" id="total"/>
</form>
</body>
哦,我稍微改了一下加号 - 对不起。
答案 2 :(得分:0)
似乎我的问题不够明确。我发布了自己的问题解决方案。它只使用jQuery,并不像一些额外的插件那样通用。但它的行为完全符合我的要求,而且我添加了在同一表单中包含远程子表单的功能。这是jsFiddle version可以使用,下面是解决方案。
现在可以更改行总和,以便根据它计算价格,反之亦然。
<!DOCTYPE html>
<html>
<head>
<title>test calculated forms</title>
<meta charset=utf-8>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<style type="text/css">
.plusminus {
font-weight: bold;
font-family: monospace;
font-size: 1.3em;
border: 1px green solid;
padding: 0px 5px;
}
</style>
<script>
$(document).ready(function(){
$('.plusminus').click(
function () {
var operation = $( this ).text();
var attr = $( this ).attr('id').split('_');
var cell_id = attr[0] + '_B_' + attr[2];
var qty = $( '#' + cell_id ).val();
if ( operation == '+' ) {
$( '#' + cell_id ).val( ++qty );
} else if ( operation == '-' ) {
$( '#' + cell_id ).val( --qty );
} else {
alert( "Something wrong! " + $( this ).attr('id') );
}
recalculate_row_sum( cell_id );
}
);
$( '.form_sum' ).on( 'change', function() {
recalculate_unit_price( $( this ).attr('id') );
});
$( '.form_price' ).on( 'change', function() {
recalculate_row_sum( $( this ).attr('id') );
});
$( '.form_discount' ).on( 'change', function() {
recalculate_row_sum( $( this ).attr('id') );
});
$( '.form_qty' ).on( 'change', function() {
recalculate_row_sum( $( this ).attr('id') );
});
init_ranges();
});
// you may have many independent ranges on same form, to init them on load is init_ranges-function
function init_ranges () {
var ranges = $( '#ranges' ).val().split( '-' );
for (var i = ranges[0]; i <= ranges[1]; i++) {
init_range_rows( i );
}
}
function init_range_rows ( range ) {
var edges = $( '#R' + range ).val().split( '-' );
for (var i = edges[0]; i <= edges[1]; i++) {
recalculate_row_sum( 'R' + range + '_C_' + i );
}
}
function recalculate_unit_price ( cell_id, data ) {
var row_data = get_row_data( cell_id, data );
var unit_price = ( row_data.row_sum/(100 -row_data.discount)*100/row_data.qty ).toFixed(2);
$( '#' + row_data.range + '_C_' + row_data.row ).val( unit_price );
recalculate_range_total( cell_id, row_data );
}
function recalculate_row_sum ( cell_id, data ) {
var row_data = get_row_data( cell_id, data );
var sum = ( row_data.unit_price*(100 - row_data.discount)/100*row_data.qty ).toFixed(2);
$( '#' + row_data.range + '_E_' + row_data.row ).val( sum );
recalculate_range_total( cell_id, row_data );
}
function recalculate_range_total ( cell_id, data ) {
var row_data = get_row_data( cell_id, data );
var edges = $( '#' + row_data.range ).val().split( '-' );
var total_amount = 0;
for (var i = edges[0]; i <= edges[1]; i++) {
total_amount += $( '#' + row_data.range + '_E_' + i ).val() * 1;
}
$( '#' + row_data.range + '_total' ).val( ( total_amount ).toFixed(2) );
}
function get_row_data ( cell_id, cached_data ) {
if ( typeof cached_data === 'defined' ) {
return cached_data;
}
var row_info = cell_id.split( '_' );
var data = {
range: row_info[0],
col: row_info[1],
row: row_info[2],
unit_price: $( '#' + row_info[0] + '_C_' + row_info[2] ).val() || 0 ,
qty: $( '#' + row_info[0] + '_B_' + row_info[2] ).val() || 0,
discount: $( '#' + row_info[0] + '_D_' + row_info[2] ).val() || 0,
row_sum: $( '#' + row_info[0] + '_E_' + row_info[2] ).val() || 0
};
return data;
}
</script>
</head>
<body>
<form id="itemlist" method="post" enctype="multipart/form-data" >
<input type="hidden" id="ranges" name="ranges" value="1-3" />
<input type="text" placeholder="Item" id="R1_A_1" name="A_1" size="20" class="form_item" value="HDD Baracuda Black 2TB" />
<span id="R1_min_1" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R1_B_1" name="B_1" value="1" size="2" class="form_qty" />
<span id="R1_plus_1" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R1_C_1" name="C_1" size="5" class="form_price" value="27" />
<input type="text" placeholder="Disc." id="R1_D_1" name="D_1" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R1_E_1" name="E_1" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Item" id="R1_A_2" name="A_2" size="20" class="form_item" value="Motherboard ASus XYZ" />
<span id="R1_min_2" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R1_B_2" name="B_2" value="1" size="2" class="form_qty" />
<span id="R1_plus_2" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R1_C_2" name="C_2" size="5" class="form_price" value="46" />
<input type="text" placeholder="Disc." id="R1_D_2" name="D_2" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R1_E_2" name="E_2" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Item" id="R1_A_3" name="A_3" size="20" class="form_item" value="Memory Kingston DDR3 4GB" />
<span id="R1_min_3" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R1_B_3" name="B_3" value="1" size="2" class="form_qty" />
<span id="R1_plus_3" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R1_C_3" name="C_3" size="5" class="form_price" value="18" />
<input type="text" placeholder="Disc." id="R1_D_3" name="D_3" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R1_E_3" name="E_3" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Total Amount" id="R1_total" name="R1_total" />
<br />
<br />
<input type="text" placeholder="Item" id="R2_A_4" name="A_4" size="20" class="form_item" value="Other foo" />
<span id="R2_min_4" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R2_B_4" name="B_4" value="1" size="2" class="form_qty" />
<span id="R2_plus_4" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R2_C_4" name="C_4" size="5" class="form_price" value="18" />
<input type="text" placeholder="Disc." id="R2_D_4" name="D_4" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R2_E_4" name="E_4" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Item" id="R2_A_5" name="A_5" size="20" class="form_item" value="Other bar" />
<span id="R2_min_5" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R2_B_5" name="B_5" value="1" size="2" class="form_qty" />
<span id="R2_plus_5" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R2_C_5" name="C_5" size="5" class="form_price" value="18" />
<input type="text" placeholder="Disc." id="R2_D_5" name="D_5" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R2_E_5" name="E_5" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Total Amount" id="R2_total" name="R2_total" />
<br />
<br />
<input type="text" placeholder="Item" id="R3_A_6" name="A_6" size="20" class="form_item" value="Some X" />
<span id="R3_min_6" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R3_B_6" name="B_6" value="1" size="2" class="form_qty" />
<span id="R3_plus_6" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R3_C_6" name="C_6" size="5" class="form_price" value="18" />
<input type="text" placeholder="Disc." id="R3_D_6" name="D_6" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R3_E_6" name="E_6" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Item" id="R3_A_7" name="A_7" size="20" class="form_item" value="Some Y" />
<span id="R3_min_7" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R3_B_7" name="B_7" value="1" size="2" class="form_qty" />
<span id="R3_plus_7" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R3_C_7" name="C_7" size="5" class="form_price" value="18" />
<input type="text" placeholder="Disc." id="R3_D_7" name="D_7" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R3_E_7" name="E_7" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Item" id="R3_A_8" name="A_8" size="20" class="form_item" value="Some Z" />
<span id="R3_min_8" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R3_B_8" name="B_8" value="1" size="2" class="form_qty" />
<span id="R3_plus_8" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R3_C_8" name="C_8" size="5" class="form_price" value="18" />
<input type="text" placeholder="Disc." id="R3_D_8" name="D_8" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R3_E_8" name="E_8" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Item" id="R3_A_9" name="A_9" size="20" class="form_item" value="Some Õ" />
<span id="R3_min_9" class="plusminus">-</span>
<input type="text" placeholder="Qty" id="R3_B_9" name="B_9" value="1" size="2" class="form_qty" />
<span id="R3_plus_9" class="plusminus" >+</span>
<input type="text" placeholder="Price" id="R3_C_9" name="C_9" size="5" class="form_price" value="18" />
<input type="text" placeholder="Disc." id="R3_D_9" name="D_9" size="3" class="form_discount" />
<input type="text" placeholder="Sum" id="R3_E_9" name="E_9" size="6" class="form_sum" />
<br />
<input type="text" placeholder="Total Amount" id="R3_total" name="R3_total" />
<input type="hidden" id="R1" name="R1" value="1-3" />
<input type="hidden" id="R2" name="R2" value="4-5" />
<input type="hidden" id="R3" name="R3" value="6-9" />
<br />
<br />
<input type="submit" name="test" value="submit all forms" />
</form>
</body>
</html>
我仍然希望在这里看到更多通用和有效的解决方案!
答案 3 :(得分:0)
您不太可能找到相应的组件,因为大多数工作流都针对单向处理进行了优化:至少有两个参数来定义结果。其他方向含糊不清。以PR = UP * Q为单位,以单价(UP),数量(Q)和价格(PR)为例。没有真正的常见用例&#34;启用PR编辑;这意味着什么:你需要计算一个新的UP = PR / Q或一个新的Q = PR / UP? (如果你现在可以决定,那并不意味着没有任何选项,或者只有另一个选择是足够的。拥有3个字段你有a = fn_a(b,c),b = fn_b( a,c)和c = fn_c(a,b)来计算值。当编辑其中一个(比如X)时,它会淘汰X = fn_X ...计算,但你还有两个可供选择的(和如果发生了真正的变化,那么通常两者都会分配不同的值。)两个公式之间的选择可能取决于输入的上下文和/或值和/或控件最后使用的顺序。这根本不是框架问题,但它是页面独特功能的一个组成部分。如果你已经设计了它应该如何工作,那么你可以从框架中获得一些的帮助.AngularJS允许你将每个控件绑定到一个属性对象,因此对象可以存储相关状态(例如,控件的使用顺序)并相应地改变其计算行为(例如,总是重新计算)最近最近输入的参数基于所有更新的参数。)
答案 4 :(得分:0)
修改html代码我在没有外部插件的情况下创建了这个脚本jQuery
Fiddle
此脚本计算tot-row,tot-group,price-per-unit,average-price,并显示最后更改的值。
可以更改行总和,并重新计算价格
可能由于我的无知,我不明白范围的问题,请你澄清一下吗?
<script type="text/javascript">
$(document).ready(function(){
$('input.Row').each(function(){$(this).val('Row nuber: '+$(this).parent('div').find('div').length)})
function calculateTot(elem){
var ind=elem.parent().index()+1
var totSum=0,averagePrice=0
var collection1=elem.parents('div').find('input.sum')
var collection2=elem.parents('div').find('input.price')
for(i=0;i<collection1.length;i++){
totSum+=parseFloat(collection1.get(i).value)
averagePrice+=parseFloat(collection2.get(i).value)
}
elem.parents('div').find('input.Amount').val(totSum.toFixed(2))
elem.parents('div').find('input.AvPrice').val((averagePrice/elem.parents('div').find('input.price').length).toFixed(2))
elem.get(0).className==='plusminus'?elem.parents('div').find('input.Change').val('Changed: Qty row:'+ind):
elem.parents('div').find('input.Change').val('Changed: '+elem.get(0).className+' row:'+ind)
}
function calculateScount(elem){
var qty =parseInt(elem.parent().find('input.qty').val())
var price=parseFloat(elem.parent().find('input.price').val())
var thisVal=parseFloat(elem.val())
var scount=(price*qty)/100*thisVal
elem.parent().find('input.sum').val((price*qty-scount).toFixed(2))
calculateTot(elem)
}
function calculate(elem){
var qty =parseInt(elem.parent().find('input.qty').val())
var price=parseFloat(elem.parent().find('input.price').val())
var scontValue=parseFloat(elem.parent().find('input.discount').val())
elem.parent().find('input.sum').val((price*qty).toFixed(2));
calculateTot(elem)
if(scontValue>0){calculateScount(elem.parent().find('input.discount'))}
}
function retro(elem){
var scontValue=parseFloat(elem.parent().find('input.discount').val())
elem.parent().find('input.price').val(parseFloat(elem.val()/elem.parent().find('input.qty').val()).toFixed(2))
calculateTot(elem)
if(scontValue>0){calculateScount(elem.parent().find('input.discount'))}
}
$('.plusminus').click(function(){
var val=$(this).text()
if(val==='+'){
var qty=parseInt($(this).prev().val())
qty++
$(this).prev().val(qty)
calculate($(this))
}
if(val==='-'&&parseInt($(this).next().val())>=1){
var qty=parseInt($(this).next().val())
qty--
$(this).next().val(qty)
calculate($(this))
}
});
$('input.qty,input.price').on('change',function(){calculate($(this))})
$('input.discount').on('change',function(){calculateScount($(this))})
$('input.sum').on('change',function(){retro($(this))})
});
</script>