001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.ajax.form;
018
019import org.apache.wicket.Component;
020import org.apache.wicket.WicketRuntimeException;
021import org.apache.wicket.ajax.AjaxRequestTarget;
022import org.apache.wicket.ajax.attributes.AjaxCallListener;
023import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
024import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
025import org.apache.wicket.markup.html.form.CheckGroup;
026import org.apache.wicket.markup.html.form.FormComponent;
027import org.apache.wicket.markup.html.form.RadioChoice;
028import org.apache.wicket.markup.html.form.RadioGroup;
029import org.apache.wicket.util.lang.Args;
030import org.danekja.java.util.function.serializable.SerializableConsumer;
031
032/**
033 * This is an Ajax behavior that is meant to update a group of choices that are represented
034 * by multiple components.
035 * <p>
036 * Use the normal {@link AjaxFormComponentUpdatingBehavior} for the normal single component fields.
037 * <p>
038 * Notification is triggered by a {@code change} JavaScript event - if needed {@link #getEvent()} can be overridden
039 * to deviate from this default.
040 * 
041 * @author jcompagner
042 * @author svenmeier
043 *
044 * @see org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior#onUpdate(org.apache.wicket.ajax.AjaxRequestTarget)
045 * @see org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior#onError(org.apache.wicket.ajax.AjaxRequestTarget, RuntimeException)
046 * @see RadioChoice
047 * @see CheckBoxMultipleChoice
048 * @see RadioGroup
049 * @see CheckGroup
050 */
051public abstract class AjaxFormChoiceComponentUpdatingBehavior extends
052        AjaxFormComponentUpdatingBehavior
053{
054        private static final long serialVersionUID = 1L;
055
056        /**
057         * Construct.
058         */
059        public AjaxFormChoiceComponentUpdatingBehavior()
060        {
061                super("change");
062        }
063
064        @Override
065        protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
066        {
067                super.updateAjaxAttributes(attributes);
068
069                attributes.setSerializeRecursively(true);
070                attributes.getAjaxCallListeners().add(new AjaxCallListener()
071                {
072                        private static final long serialVersionUID = 1L;
073
074                        @Override
075                        public CharSequence getPrecondition(Component component)
076                        {
077                                return String.format("return attrs.event.target.name === '%s'", getFormComponent().getInputName());
078                        }
079                });
080        }
081
082        /**
083         * 
084         * @see org.apache.wicket.behavior.AbstractAjaxBehavior#onBind()
085         */
086        @Override
087        protected void onBind()
088        {
089                super.onBind();
090
091                if (getComponent() instanceof RadioGroup || getComponent() instanceof CheckGroup)
092                {
093                        getComponent().setRenderBodyOnly(false);
094                }
095        }
096
097        @Override
098        protected void checkComponent(FormComponent<?> component)
099        {
100                if (!AjaxFormChoiceComponentUpdatingBehavior.appliesTo(getComponent()))
101                {
102                        throw new WicketRuntimeException("Behavior " + getClass().getName() +
103                                " can only be added to an instance of a RadioChoice/CheckboxChoice/RadioGroup/CheckGroup");
104                }
105        }
106
107        /**
108         * @param component
109         *            the component to check
110         * @return if the component applies to the {@link AjaxFormChoiceComponentUpdatingBehavior}
111         */
112        static boolean appliesTo(Component component)
113        {
114                return (component instanceof RadioChoice) ||
115                        (component instanceof CheckBoxMultipleChoice) || (component instanceof RadioGroup) ||
116                        (component instanceof CheckGroup);
117        }
118
119        /**
120         * Creates an {@link AjaxFormChoiceComponentUpdatingBehavior} based on lambda expressions
121         * 
122         * @param onUpdateChoice
123         *            the {@code SerializableConsumer} which accepts the {@link AjaxRequestTarget}
124         * @return the {@link AjaxFormChoiceComponentUpdatingBehavior}
125         */
126        public static AjaxFormChoiceComponentUpdatingBehavior onUpdateChoice(
127                SerializableConsumer<AjaxRequestTarget> onUpdateChoice)
128        {
129                Args.notNull(onUpdateChoice, "onUpdateChoice");
130                return new AjaxFormChoiceComponentUpdatingBehavior()
131                {
132                        private static final long serialVersionUID = 1L;
133
134                        @Override
135                        protected void onUpdate(AjaxRequestTarget target)
136                        {
137                                onUpdateChoice.accept(target);
138                        }
139                };
140        }
141}