Я разрабатываю веб-приложение Grails, модули которого, в основном, должны реализовывать интерфейс master-detail. В качестве подхода я хочу представить на рассмотрение следующий код:
Мастер-класс:
import org.codehaus.groovy.grails.web.json.JSONArray
class MyForm {
String name
String address
String detail
BigDecimal total
static hasMany = [details: MyFormDetail]
static constraints = {
name()
address()
detail()
total()
}
static mapping = {
detail type: 'text'
}
def beforeInsert = {
def detailJSON = new JSONArray(detail)
detailJSON.each {
def quantity = it.getAt("quantity").toString().toBigDecimal()
def description = it.getAt("description").toString()
def unitaryPrice = it.getAt("unitaryPrice").toString().toBigDecimal()
def subtotal = it.getAt("subtotal").toString().toBigDecimal()
def myFormDetail = new MyFormDetail(
quantity: quantity,
description: description,
unitaryPrice: unitaryPrice,
subtotal: subtotal
)
this.addToDetails(myFormDetail)
}
}
}
Подробный класс:
class MyFormDetail {
Integer quantity
String description
BigDecimal unitaryPrice
BigDecimal subtotal
static belongsTo = [myForm: MyForm]
static constraints = {
quantity()
description()
unitaryPrice()
subtotal()
}
}
myFormUtilities. js вспомогательный файл:
$(document).ready(function() {
$("#detailTable").jqGrid({
datatype: "local",
height: 100,
colNames: ["QUANTITY","DESCRIPTION","UNIT. PRICE","SUBTOTAL"],
colModel:[
{name:'quantity',index:'quantity', width:100},
{name:'description',index:'description', width:400},
{name:'unitaryPrice',index:'unitaryPrice', width:100},
{name:'subtotal',index:'subtotal', width:100}],
caption: "DETAIL"
});
createTable();
$("#addRow").bind("click",addRow);
$("#removeRow").bind("click",removeRow);
$("#quantity, #unitaryPrice").bind("keyup",calculateTotal);
function calculateTotal(){
let quantity = parseFloat($("#quantity").val());
let unitaryPrice = parseFloat($("#unitaryPrice").val());
let subtotal = quantity*unitaryPrice;
$("#subtotal").val(subtotal);
}
function addRow(){
let row = new Object();
row.quantity = $("#quantity").val();
row.description = $("#description").val();
row.unitaryPrice = $("#unitaryPrice").val();
row.subtotal = $("#subtotal").val();
let detailJSON = ($("#detail").val()=="")?"[]":$("#detail").val();
let mydata = $.parseJSON(detailJSON);
mydata.push(row);
$("#detail").val(JSON.stringify(mydata));
createTable();
}
function removeRow(){
let filaId = parseInt($('#detailTable').jqGrid('getGridParam','selrow')) - 1;
let mydata = $.parseJSON($("#detail").val());
let nuevoMydata = new Array();
for(let i=0;i<mydata.length;i++){
if(filaId!=i)
nuevoMydata.push(mydata[i]);
}
$("#detail").val(JSON.stringify(nuevoMydata));
createTable();
}
function createTable(){
let total = 0;
let aRow = new Object();
let detailJSON = ($("#detail").val()=="")?"[]":$("#detail").val();
let mydata = $.parseJSON(detailJSON);
$("#detailTable").jqGrid("clearGridData", true);
for(let i=0;i<mydata.length;i++){
aRow = mydata[i];
total += parseFloat(aRow.subtotal);
$("#detailTable").jqGrid('addRowData',i+1,aRow);
}
$("#total").val(total);
}
});
Это отображаемая форма (я знаю, что это автоматически сгенерированное представление, но считаю его очень основополагающим c GUI макет, пожалуйста):
Итак, вот эти проблемы:
И Subtotal
и Total
поля - это вычисляемые поля, которые были установлены read-only
для предотвращения изменения пользователем своего контента, но я обнаружил, что с помощью инспектора элементов браузера их содержимое и свойства (например, только для чтения) можно изменять.
То же самое происходит с detail
. Если его содержимое изменяется, при сохранении экземпляра будет возникать ошибка на стороне сервера, поскольку блоку beforeInsert
требуется действительная строка JSON для создания экземпляров detail
. Это поле также используется для генерации детализации JqGrid. Это поле будет скрыто.
Все в этом примере работает должным образом, но любопытный пользователь может вызвать ошибку.
- Есть ли способ чтобы предотвратить изменение текста этих полей даже с помощью инспектора?
- Есть ли еще место , чтобы защитить эти данные от изменений?
- Я использую это
detail
поле для сохранения строки JSON, и это мое решение для реализации шаблона master-detail. Есть ли другой способ улучшить эту реализацию, избегая необходимости определять поле для этой строки?