質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

jsでajaxCompleteが2回実行されてしまう

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 731

score 47

WPのwooccomerceを使っています。
背景として、カートページの商品数量を変更するのに、プラス、マイナスボタンのUIを作り、
それを押す度にカート内がajax更新され、数量が反映されます。しかし僕自身ajaxの知見はほぼなく、woocommerceの仕様で実行されているに過ぎません。

1回目のクリックイベントは問題ないのですが、ajax更新後にそのUIのclickイベントが機能しなくなったので、
「ajaxComplete」を使ったクリックイベントを追記して対処したのですが、なぜかajaxCompleteの中身が2回実行されてしまいます。

以下、「商品の数量変更UI」と「カート更新ボタン」です。
カート更新ボタンはデフォルトで用意されていましたが、

///数量変更UI

<form class="woocommerce-cart-form" action="<?php echo esc_url( wc_get_cart_url() ); ?>" method="post">
    <?php do_action( 'woocommerce_before_cart_table' ); ?>

    <table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents" cellspacing="0">
        <tbody>
            <?php do_action( 'woocommerce_before_cart_contents' ); ?>

<!-- ~~~~~~~~~~~~~~略~~~~~~~~~~~~~~ -->

<!-- 商品の数量変更UI -->
<td class="product-quantity" data-title="<?php esc_attr_e( 'Quantity', 'woocommerce' ); ?>">
    <div class="shop__num">
<!-- マイナスボタン -->
        <div type="button" class="minus shop__num__count cart__count--down">-</div>
        <?php
        if ( $_product->is_sold_individually() ) {
            $product_quantity = sprintf( '1 <input class="qty" type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key );
        } else {
            $product_quantity = woocommerce_quantity_input(
                array(
                    'input_name'   => "cart[{$cart_item_key}][qty]",
                    'input_value'  => $cart_item['quantity'],
                    'max_value'    => $_product->get_max_purchase_quantity(),
                    'min_value'    => '0',
                    'product_name' => $_product->get_name(),
                ),
                $_product,
                false
            );
        }

        echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item ); // PHPCS: XSS ok.
        ?>
<!-- プラスボタン -->
        <div type="button" class="plus shop__num__count cart__count--up">+</div>
    </div>
</td>

<!-- ~~~~~~~~~~~~~~略~~~~~~~~~~~~~~ -->

<!-- カートの中身変更ボタン -->
<tr>
    <td colspan="6" class="actions">

        <?php if ( wc_coupons_enabled() ) { ?>
            <div class="coupon">
                <label for="coupon_code"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e( 'Coupon code', 'woocommerce' ); ?>" /> <button type="submit" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?>"><?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?></button>
                <?php do_action( 'woocommerce_cart_coupon' ); ?>
            </div>
        <?php } ?>

        <button type="submit" class="button" name="update_cart" value="<?php esc_attr_e( 'Update cart', 'woocommerce' ); ?>"><?php esc_html_e( 'Update cart', 'woocommerce' ); ?></button>

        <?php do_action( 'woocommerce_cart_actions' ); ?>

        <?php wp_nonce_field( 'woocommerce-cart', 'woocommerce-cart-nonce' ); ?>
    </td>
</tr>

<!-- ~~~~~~~~~~~~~~略~~~~~~~~~~~~~~ -->

<?php do_action( 'woocommerce_after_cart_contents' ); ?>
        </tbody>
    </table>
<?php do_action( 'woocommerce_after_cart_table' ); ?>
</form>

以下jsです。
「初期のクリックイベント」と「ajaxロード後のクリックイベント時」を書いています。

「ajax後のクリックイベント」が2回実行されるので、
2個プラス、2個マイナスみたいになってしまいます。

  //初期クリックイベント
  var $cart_count = $('.shop__num'),
      $count_now = $('.shop .qty'),
      $count_down = $('.cart__count--down'),
      $count_up = $('.cart__count--up');

  var step = 1;
  var min = 1;
  var max = 100;

  $count_down.each(function(){
    $(this).on('click', function() {
      console.log('-');
      var num = $(this).next('.quantity').find('input').val();
      num--;
      if ( num < min ) {
        num = min;
      };
     $(this).next('.quantity').find('input').val(num);
      $('[name=update_cart]').prop({'disabled': false, 'aria-disabled': false });
      jQuery("[name='update_cart']").trigger("click");
    });
  });

  $count_up.on('click', function() {
    console.log('+');
    var num = $(this).prev('.quantity').find('input').val();
    num++;
    if ( max < num ) {
      num = max;
    };
    $(this).prev('.quantity').find('input').val(num);
    $('[name=update_cart]').prop({'disabled': false, 'aria-disabled': false });
    jQuery("[name='update_cart']").trigger("click");
  });

  //ajaxロード後のイベント
  jQuery(document).ajaxComplete(function(){
    console.log('ajax!!!');
    var $cart_count = $('.shop__num'),
        $count_now = $('.shop .qty'),
        $count_down = $('.cart__count--down'),
        $count_up = $('.cart__count--up');

    var step = 1;
    var min = 1;
    var max = 100;

    $count_down.each(function(){
      $(this).on('click', function() {
        console.log('ajax--');
        var num = $(this).next('.quantity').find('input').val();
        num --;
        if ( num < min ) {
          num = min;
        };
        console.log('ajaxマイナスした');////1クリックでこいつが2回logされる。
       $(this).next('.quantity').find('input').val(num);
        $('[name=update_cart]').prop({'disabled': false, 'aria-disabled': false });
        jQuery("[name='update_cart']").trigger("click");
      });
      return false;
    });

    $count_up.on('click', function() {
      console.log('ajax++');
      var num = $(this).prev('.quantity').find('input').val();
      num ++;
      if ( max < num ) {
        num = max;
      };
      console.log('ajaxプラスした');////1クリックでこいつが2回logされる。
      $(this).prev('.quantity').find('input').val(num);
      $('[name=update_cart]').prop({'disabled': false, 'aria-disabled': false });
      jQuery("[name='update_cart']").trigger("click");
      return false;
    });
  });

以上がコードになります、なぜ「ajaxロード後のイベント」の中身は2回実行されてしまうのでしょうか?
ご教授いただけると幸いです。(情報の不足があればおっしゃってください)

よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • umau

    2021/01/24 19:23

    form タグと、送信処理を行っているところのスクリプトを示してもらえますか。

    キャンセル

  • Yariii

    2021/01/24 23:50

    formタグ追記しました。送信処理は、<!--カートの中身変更ボタン-->にあるsubmitタイプのbuttonが担っているようです。

    キャンセル

  • umau

    2021/01/25 00:36

    送信処理はプラグインがイベント追加してるのかもしれないですね。submit押下だけなら普通にformのpost処理になってAjaxじゃない事になりますし。wooccomerceを知らないので分からないですが。
    送信処理側の可能性は見切れないので無視することにして、見て分かる内容で回答してみます。

    キャンセル

回答 2

check解決した方法

0

https://johnhashim.com/posts/add-plus-and-minus-ajax-buttons-to-woocommerce-quantity-inputs/

こちらの記事を参考に解決できました。ちょっと別のアプローチです。
woocommerceのglobalフォルダに、数量変更する共通UIがあり、そこに+-ボタンを作成するイメージです。
jQueryは記事とおりfunctions.phpに追記しました。(woocommerceの場合phpでフックをかけないとjsが理想通り動かないのかな...)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

ajaxCompleteの中と外の2カ所でクリックイベントが付けられているので、一度ajaxCompleteの中を通るとクリックイベントが2個になります。

で、そのどちらのイベント関数も最後にupdate_cart ボタンのクリックをトリガーしています。
1クリックで2個とも実行され、2回updaete_cartがトリガー実行されてしまう、という事に思えます。

※通常、標準のaddEventListnerは同じイベントは1つしか付けれないので、clickイベントを2回付けると上書きされて1個になるんですが、jQueryのon()でのイベント追加は複数バインドが可能で、バインドした順にリスナーが呼び出されます。(jQueryが内部にリスナー関数を保持する)

ajaxComplete内でのイベント追加が不要なんじゃないでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/01/25 13:38

    ajaxロードされたあと、なぜか外側のjsイベントが効かなくなったんですよね、、なのでajaxCompleteの内側にイベント処理を追記したのですが、logを使ってコンソール確認してみるとやはり外側のクリックイベントは2回目以降は効いていないみたいです。

    ちょっと全く別の代替案ですが、理想の動きにできた方法があったので、今回はこちらで解決済みにさせていただこうと思います。
    ご回答ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る