0

私はSpring MVCで作業しています.Myコマンドオブジェクトにはコレクションオブジェクトが含まれています.次のようになります

public class DimensionStoneBean {
int stoneNo;
float length;
float breadth;
float height;
float dimension;
String isIssued;

public int getStoneNo() {
    return stoneNo;
}
public void setStoneNo(int stoneNo) {
    this.stoneNo = stoneNo;
}
public float getLength() {
    return length;
}
public void setLength(float length) {
    this.length = length;
}
public float getBreadth() {
    return breadth;
}
public void setBreadth(float breadth) {
    this.breadth = breadth;
}
public float getHeight() {
    return height;
}
public void setHeight(float height) {
    this.height = height;
}
public float getDimension() {
    return dimension;
}
public void setDimension(float dimension) {
    this.dimension = dimension;
}
public String getIsIssued() {
    return isIssued;
}
public void setIsIssued(String isIssued) {
    this.isIssued = isIssued;
}

}





    public class UpdateStockBean {
@SuppressWarnings("rawtypes")
private List dimensionStones =
    LazyList.decorate(new LinkedList(),FactoryUtils.instantiateFactory(DimensionStoneBean.class));
long openbalance;

public UpdateStockBean() {
    super();
}

@SuppressWarnings("rawtypes")
public List getDimensionStones() {
    return dimensionStones;
}
public void setDimensionStones(@SuppressWarnings("rawtypes") List dimensionStones) {
    this.dimensionStones = dimensionStones;
}
public long getOpenbalance() {
    return openbalance;
}
public void setOpenbalance(long openbalance) {
    this.openbalance = openbalance;
}

}

このコントローラ クラスは、AbstractWizardFormControllerを拡張します。

formBackingObject() コマンドオブジェクトを作成してフォームに返すために使用しました

フォームは次のようになります

  <form:form commandName="updateStock" method="post" name="stockEntry" action="updateStock.nic" id="updateStock">
  <br><br><br>
  <table border="1" width="700">
   <tr>     
     <td class="textClr1" align="left" width="50"><nobr>Total No Of Stones</nobr></td>
     <td colspan="6"><form:input tabindex="1" path="openbalance" id="openbalance" cssClass="controlStock"/></td>
   </tr>    
   <tr>
      <td></td>
      <td colspan="6"><form:errors cssClass="error" path="openbalance"/></td>
   </tr> 
  </table>
  <table>
   <tr>
     <td colspan="3">
        <table  border="1" width="400">
          <tbody id="dimensionList">                           
            <c:forEach  var="DimensionStones" items="${updateStock.dimensionStones}" varStatus="i" begin="0">
              <tr class="dimensionStone">    
                 <td><form:input path="dimensionStones[${i.index}].stoneNo" id="stoneNo${i.index}" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].length" id="length${i.index}" onchange="findDimension(this.id)" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].breadth" id="breadth${i.index}" onchange="findDimension(this.id)" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].height" id="height${i.index}" onchange="findDimension(this.id)" cssClass="controlStock"/></td>
                 <td><form:input path="dimensionStones[${i.index}].dimension" id="dimension${i.index}" cssClass="controlStock"/></td>                 
                 <td><form:checkbox path="dimensionStones[${i.index}].isIssued" id="isIssued${i.index}" value="" cssClass="check"/></td>
                 <td><a href="#" class="removeDimensionStone"><img src="images/cross1.jpg" width="20" height="20" title="Remove Dimension Stone"/></a></td>

              </tr>
            </c:forEach>   
            <tr>

            </tr>             
            <c:if test="${empty updateStock.dimensionStones}">
                <tr class="dimensionStone defaultRow">    
                            <td><input type="text" name="dimensionStones[].stoneNo" value="" id="stoneNo" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].length" value="" id="length" onchange="findDimension(this.id)" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].breadth" value="" id="breadth" onchange="findDimension(this.id)" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].height" value="" id="height" onchange="findDimension(this.id)" Class="controlStock"/></td>
                            <td><input type="text" name="dimensionStones[].dimension" value="" id="dimension" disabled="disabled" Class="controlStock"/></td>                            
                            <td><input type="checkbox" name="dimensionStones[].isIssued" value="Yes" id="isIssued" Class="controlStock"/></td> 
                            <td><a href="#" class="removeDimensionStone"><img src="images/cross1.jpg" width="20" height="20" title="Remove Dimension Stone"/></a></td>
                        </tr>
            </c:if>   
           </tbody>  
         </table>           
       </td>    
    </tr>    
  </table>
  <table  border="1" width="600"> 
   <tr>
      <td colspan="3" align="left"><a href="#" id="addDimensionStone"><img src="images/plus3.png" width="20" height="20" title="Add Dimension Stone"/></a></td>
   </tr> 
   <tr></tr> 
   <tr></tr> 
   <tr>
     <td colspan="3" align="center" width="200" height="180">
      <input type="submit" name="_target0" value="Submit" class="butn" />
     </td>
    </tr>  
  </table>  
</form:form>

これにより、コマンド オブジェクトのコレクションの値が表示され、新しい行の削除、編集、および追加が可能になります。

しかし、私の問題は、削除しても、コマンドオブジェクトのコレクション内の対応するオブジェクトがクリアされないことです。その結果、不要な DIMENSIONSTONE オブジェクトが発生します。

4

1 に答える 1

0

項目の削除は、Spring を使用してコレクションにバインドする際の問題です。問題は、コマンド オブジェクトが存続し、コレクションから特定の項目を削除するように WebBinder に指示する方法が UI 側にないことです。本質的に、ビューから渡されたインデックス/キーを指定して、指定された位置に物を挿入することのみを処理できます。

この制限を回避するために、私が過去に行ったことは、コレクション内の豆に「除去」と呼ばれるブール値を追加することでした。次に、オブジェクトを削除するときに、HTML DOM を次のような隠しフィールドに置き換えるだけです。

<input type="hidden" name="beans[3].removal" value="true" />

次に、コントローラーで、コレクションをループして、「削除」フラグが設定されているものを削除します。

もう 1 つの方法は、合計数をコマンド オブジェクトに格納することです。次に、コントローラーに到達したら、そのカウントの後にコレクションを単純に切り捨てます。

編集:例(私の頭から)

コマンド オブジェクト:

public class FormBean {
  private List<MyBean> myBeans;
  // ...getters/setters etc
}

コマンド オブジェクトのコレクション内の Bean:

public class MyBean {
  private String someProperty;
  private Integer someOtherProperty;

  private boolean removal;
  // Getters/Setters
}

形:

<!-- standard HTML stuff -->
<script>
  $(document).ready(function() {
    // Click handler to replace the contents of div.row with the removal flag
    $('.btnRemove').click(function() {
      var count = $(this).parent().prev('.row').length;
      $(this).parent().removeClass('rowActive').addClass('rowRemove');
      $(this).parent().hide();
      $(this).parent().html(function() {
        return $("<input/>",{
          id: 'myBeans'+count+'.removal',
          name: 'myBeans['+count+'].removal',
          value: 'true'
        });
      });
    });
  });
</script>
<!-- More HTML stuff -->
<form:form modelAttribute="formBean" action="/someUrl">
  <c:forEach items="${formBean.myBeans}" var="myBean" varStatus="status">
    <div class="row rowActive">
      <form:input path="myBeans[${status.index}].someProperty" />
      <input type="button" class="btnRemove" value="Remove" />
    </div>
  </c:forEach>
</form:form>

次に、コントローラ コードのどこかで次のようにします。

Set<MyBean> removals = new HashSet<MyBean>();
for(MyBean myBean : formBean.getMyBeans) {
  if(myBean.isRemoval) {
    removals.add(myBean);
  }
}
formBean.getMyBeans().removalAll(removals);

最初に、これをメモリから完全に投稿編集ボックスに直接入力しました。走行距離は異なる場合があります...

2 番目: jQuery を使用します。できません。必要に応じて、jQuery のものを適切な非 jQuery のものに置き換えます。

3番目:私が磨き上げたいくつかの部分があります. たとえば、div に「行」クラスがある理由は、追加するインデックスを知る必要があるため、新しい行を追加するための合計数を取得できるようにするためです。div の "rowActive" および "rowRemove" クラスは、たとえばアイテムが 1 つしか残っていないときに削除ボタンを無効にするなど、他のことのカウントを取得するために使用されます。私が行っていない他のことは、行の追加とイベント ハンドラーの設定です (イベント ハンドラーを必要とする新しいボタンを追加するため、DOM を変更するたびに行う必要があります)。アプリ全体があなたのためです。ここまで来たら、これらのことを理解できると思います。

私は約 6 つの異なる Spring MVC アプリケーションでこのアプローチを使用しました。JavaScript は複雑で、要素を手動で追加および削除する必要があります。しかし、これは、Spring MVC を使用してコレクションからアイテムを追加および削除することをサポートするために私が見つけた最良の方法です。私の場合、ValidationService オブジェクトを使用して独自の検証を行っているため、Controller 側のクリーンアップは大きな問題ではありません。そこでクリーンアップ ルーチンをスローするだけです。他のより良いアプローチがあれば、ぜひ見てみたいです。

AJAX を使用している場合 (私たちは使用していないため、サーバーへの往復リクエストを許可するソリューションが必要でした)、コレクション内のアイテムの追加/削除を処理する CRUD メソッドを提供することで、プロセスを大幅に簡素化できます。

編集:情報を更新しています

この回答を維持するために、私はそれ以来、この jQuery 部分の戦術を切り替えたことに注意したいと思いました。DOM 要素を直接作成する代わりに、.clone()といくつかの創造的な正規表現を使用して新しい要素を作成し、それらの名前を変更して ID を変更することが好きになりました。これを行う利点は、私見ですが、深いクローンを作成してDOMのブロック全体を一度に取得できるため、コードが大幅に削減されることです。たとえば、テーブルがあり、それに行全体を追加しようとしていた場合、次のようにすることができます。

function addTableRow() {
  var $lastActiveRow = $('#myTable tr.rowActive:last-child');  // Gets the last active row
  var newActiveRow = $lastActiveRow.clone();
  var count = $('#myTable tr.rowActive').length;

  // Fix the name and identifier of all inputs in the new row
  $(newActiveRow).find(':input').each(function() {
    var name = $(this).attr('name');
    var identifier = $(this).attr('id');
    $(this).attr('name',name.replace(/(\d+)/g,count));  // matches and replaces digits that look like "xxx[1]"
    $(this).attr('id',identifier.replace(/(\d+)/g,count));  // matches and replaces digits that look like "xxx1"
  });
  $('#myTable').append(newActiveRow);
}

したがって、この例では、最初にテーブルの最後のアクティブな行を取得し、次にその行を複製します。次に、その行の入力をループし、正規表現とすべてのアクティブな行のカウントを使用して名前と ID をリセットします。私の以前の方法を使用すると、jQuery は非常に複雑な DOM ツリーを追加しようとしてすぐに手に負えなくなります。

注意すべき点: まず、jQueryclone()メソッドは IE 7 以前では壊れており、これらのバージョンの IE で問題が発生しています。また、 each() ループは入力の値をまったくリセットしませんでした。複製された入力は、複製元の入力と同じ値を持つため、それを行う必要があります。

clone()最後に、このメソッドはデフォルトでイベント ハンドラーを複製しないため、jQuery イベント ハンドラーをアタッチしたボタンなども機能しないことを指摘したいと思います。ブール値を渡してjQueryclone()にイベントを指示することもできますが、イベントが間違った要素によって処理されるという問題があります(イベントハンドラーは複製されず、要素だけですが、古いハンドラーが適用されます新しい要素なので、交差したハンドラーになります)。より良い解決策は、ハンドラーをより高いレベルの要素にアタッチして、委任されたイベントを使用することです (ダイレクト イベントと委任されたイベントのセクションを参照してください)。

于 2013-03-08T20:57:09.070 に答える