3

私のフォームにはアイテムのリストがあり、各アイテムには削除ボタンがあります。削除するアイテムのインデックスと、フォームの他の値を送信する必要があります (さらに編集するため)。

JavaScript では、次のようになります。

<g:form method="post" mapping="defaultAction" id="${paymentInstance?.id}">
    <g:hiddenField name="id" value="${paymentInstance?.id}"/>
    <g:hiddenField name="version" value="${paymentInstance?.version}"/>
    <g:hiddenField name="deleteAdjIdx"/>
    <g:each in="${paymentInstance?.adjustments}" var="adj" status="idx">
        <g:set var="adjName" value="adjustments[${idx}]"/>
        <g:textField name="${adjName}.dollars" value="${adj.dollars}"/>
        <g:actionSubmit action="deleteAdj" value="delete" onclick="jQuery('#deleteAdjIdx').val(${idx})"/>
    </g:each>
</g:form>

JavaScript なしでこれを行うにはどうすればよいですか? (投稿されたパラメーターに加えて、URL にパラメーターを追加できますか? または、マッピングにある種のマルチプレックスを追加できますか?)

defaultAction マッピングは次のとおりです。

    name defaultAction: "/$controller/$id"{     // stable URL for payments regardless of current status (editable or not)
        constraints {
            id(matches: /\d+/)      // since our action names don't start with a digit but many domain ids do
        }
    }
4

4 に答える 4

1

私はちょうど同じ問題を抱えていて、HTML5 の "formaction" 属性を使用して別の解決策を見つけました。コントローラー、アクション、追加パラメーターなどを含む値を指定できます。

一般に、フォームの送信ボタン (特定のサブオブジェクトの削除など) にパラメーターを追加するには、次のようにします。

<input type="submit" formaction="/<controller>/<action>/<id>?additionalParam1=...&additionalParam2=..." value="Delete" >

そしてあなたの例では:

<input type="submit" formaction="/payment/deleteAdj/${adj.id}" value="delete" >

また

<input type="submit" formaction="/payment/deleteAdj?delAdjID=${adj.id}" value="delete" >

deleteAdj では、params.id または params.delAdjID に記述されている調整を削除し、params 内にデータを保存するか、params を直接使用してフォームを再入力します (たとえば、create.gsp をレンダリングするとき)。

于 2013-08-14T16:54:46.697 に答える
0

使用できる送信ボタンは1つg:eachだけで、をradioGroup

例:

<g:radioGroup name="adj" labels="[put here your text]" values="[put here the indexes]">
   <p>${it.label} ${it.radio}</p>
</g:radioGroup>

adj削除するアイテムの値を保持します

于 2012-05-26T02:55:09.710 に答える
0

actionSubmit のアクション名にパラメーターを追加してみます。

<my:actionSubmit action="deleteAdj" value="delete" params="${[deleteAdjIdx: idx]})"/>

これを行う良い方法が見つからなかったので、次のハックを思いつきました。誰かが改善点を知っていれば、私はそれを感謝します。

MyTagLib に追加:

import org.codehaus.groovy.grails.web.util.WebUtils

def actionSubmit = { attrs ->
    String action = attrs.action ?: attrs.value
    Map params = attrs.remove('params')
    if (params) {
        attrs.action = (action + WebUtils.toQueryString(params)).encodeAsURL()
    }
    out << g.actionSubmit(attrs)
}

パラメータを解凍し、フィルタで元のアクション名を復元します。

package com.example;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.web.filter.GenericFilterBean
import org.codehaus.groovy.grails.web.util.WebUtils
import com.example.util.MyWebUtils
import javax.servlet.http.HttpServletRequest;

/**
 * Handles params packed into the MyTagLib.actionSubmit param name.
 * This Filter needs to come before GrailsWebRequestFilter.
 * <p/>
 * Updating the GrailsParameterMap after the GrailsWebRequestFilter doesn't work,
 * because the request given to DefaultUrlMappingInfo.checkDispatchAction()
 * is the immutable request saved in the GrailsWebRequest, not the wrapped request
 * that this filter passes on down the chain.
 */
public class ActionSubmitParamFilter extends GenericFilterBean {

    final static QUERY_SEPARATOR = '?'
    final static QUERY_SEPARATOR_REGEX = '[?]'
    final static PARAM_SEPARATOR_REGEX = '[&]'

    @Override
    void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        def dispatchAction = request.parameterNames.find {it.startsWith(WebUtils.DISPATCH_ACTION_PARAMETER)}
        def decoded = dispatchAction?.decodeURL()
        if (decoded?.contains(QUERY_SEPARATOR)) {
            def overrides = unpackParams(decoded)
            overrides[dispatchAction] = null   // deletes from the overridden request params
            request = MyWebUtils.overrideParams((HttpServletRequest) request, overrides)
        }
        chain.doFilter(request, response);
    }

    private Map unpackParams(String decoded) {
        String action, paramsPart
        (action, paramsPart) = decoded.split(QUERY_SEPARATOR_REGEX)
        assert action.startsWith(WebUtils.DISPATCH_ACTION_PARAMETER)
        def packedParams = [:].withDefault {[]}
        packedParams[action] << ''

        for (param in paramsPart.split(PARAM_SEPARATOR_REGEX)) {
            if (param.contains('=')) {
                def (name, value) = param.split('=')
                packedParams[name.decodeURL()] << value.decodeURL()
            } else {
                packedParams[param.decodeURL()] << ''
            }
        }
        packedParams
    }
}

リクエスト パラメータをオーバーライドしてフィルタを設定するユーティリティ メソッドを作成しました。

package com.example.util

import org.springframework.web.multipart.MultipartHttpServletRequest
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletRequestWrapper
import groovy.util.slurpersupport.GPathResult
import com.example.ActionSubmitParamFilter

class MyWebUtils {

    static HttpServletRequest overrideParams(HttpServletRequest original, Map<String, List<String>> overrides) {
        assert !(original instanceof MultipartHttpServletRequest)   // if we get one of these, we'll need to use a special wrapper

        def params = (Map<String, String[]>) new HashMap(original.getParameterMap())
        overrides.each {k, v ->
            if (v == null) {
                params.remove(k)    // significant for parameterNames enumeration and parameterMap
            } else {
                params[k] = v as String[]
            }
        }
        params = Collections.unmodifiableMap(params)
        new HttpServletRequestWrapper(original) {

            @Override
            String[] getParameterValues(String name) {
                params[name]
            }

            @Override
            String getParameter(String name) {
                String[] values = params[name]
                values ? values[0] : (values == null ? null : '')
            }

            @Override
            Map getParameterMap() {
                params
            }

            @Override
            Enumeration getParameterNames() {
                Collections.enumeration(params.keySet())
            }
        }
    }


    // used dynamically by _Events.eventWebXmlStart
    static void prependActionSubmitParamFilter(GPathResult webXml) {

        def filters = webXml.filter
        def filterMappings = webXml.'filter-mapping'

        def firstFilter = filters[0]
        def firstFilterMapping = filterMappings[0]

        firstFilter + {
            filter {
                'filter-name'('actionSubmitParam')
                'filter-class'(ActionSubmitParamFilter.name)
            }
        }

        firstFilterMapping + {
            'filter-mapping' {
                'filter-name'('actionSubmitParam')
                'url-pattern'("/*")
                'dispatcher'("FORWARD")
                'dispatcher'("REQUEST")
            }
        }
    }
}

最後に、_Events.groovy に以下を追加して、ControllersGrailsPlugin.doWithWebDescriptor を拡張して web.xml でフィルターを構成します。

eventWebXmlStart = {

    pluginManager.getGrailsPlugin('controllers').with {
        def originalClosure = instance.doWithWebDescriptor  // extending
        instance.doWithWebDescriptor = { GPathResult webXml ->

            // static import fails after clean (before compile), so load dynamically
            def webUtils = getClass().classLoader.loadClass('com.example.util.MyWebUtils')
            webUtils.prependActionSubmitParamFilter(webXml)

            // call super after (so above filter comes before GrailsWebRequestFilter in chain)
            originalClosure.resolveStrategy = Closure.DELEGATE_FIRST
            originalClosure.delegate = delegate
            originalClosure(webXml)
        }
    }
}
于 2012-06-08T00:28:14.083 に答える
0

あなたのコードはいくつかの削除ボタンを作成し、各ボタンをクリックするとページがリロードされるようです。

では、いくつかのフォームを作成してみませんか。

<g:each in="${paymentInstance?.adjustments}" var="adj" status="idx">
    <g:form method="post" mapping="defaultAction" id="${paymentInstance?.id}">
        <g:hiddenField name="id" value="${paymentInstance?.id}"/>
        <g:hiddenField name="version" value="${paymentInstance?.version}"/>
        <g:hiddenField name="deleteAdjIdx" value="${idx}"/>
        <g:set var="adjName" value="adjustments[${idx}]"/>
        <g:textField name="${adjName}.dollars" value="${adj.dollars}"/>
        <g:actionSubmit action="deleteAdj" value="delete" />
    </g:form>
</g:each>

更新

単一のフォームが必要な場合は、通常の送信ボタンを使用することもできます。フォームに固定アクションを指定し、送信ボタンに値を指定します。

<g:form method="post" 
        controller="payment" action="myAction" 
        id="${paymentInstance?.id}">
    <g:each in="${paymentInstance?.adjustments}" var="adj" status="idx">
        <g:hiddenField name="id" value="${paymentInstance?.id}"/>
        <g:hiddenField name="version" value="${paymentInstance?.version}"/>
        <g:set var="adjName" value="adjustments[${idx}]"/>
        <g:textField name="${adjName}.dollars" value="${adj.dollars}"/>
        <input type="submit" name="delete" value="${idx}"/>
    </g:each>
</g:form>

これにより、paymentコントローラーとによって処理されるフォームが生成されmyActionます。このアクションでは、params.delete存在するかどうかを確認できます。このパラメータの値は の値になります${idx}

このフォームに他のアクションが必要な場合は、同じ方法で他の送信ボタンを追加し、params-value の存在を確認するだけです。その後、コントローラーの別のアクションにジャンプできます (これが、これらの<g:actionSubmit .../>ボタンがバックグラウンドで処理される方法です。

更新 2: あなたの言うとおりです。ボタンにインデックスを表示するのは見苦しいです。したがって、別の方法は、最初の更新のコードを使用して、ボタンを次のように変更することです。

        <input type="submit" name="delete_${idx}" value="Delete me!"/>

コントローラーでは、次のようなコードを使用する必要があります

def idx = null
params.each { key, value ->
  if (key.startsWith('delete_')) {
    idx = key-"delete_"
  }
}
if (idx) {
  // delete element
}

または、よりグルーヴなバージョンを好む場合

def idx = (params.find { key, value -> key.startsWith('delete_')})?.key
if (idx) {
  id -= 'delete_'
  // delete element
}

さらに難読化されています:-)

def idx = ''+(params.find { key, value -> key.startsWith('delete_')})?.key-'null'-'delete_'
if (idx) {
  // delete element
}
于 2012-05-25T05:44:36.337 に答える