Angular click debounce












0















In my template I have field and two buttons:



<div class="btn-plus" (click)="add(1)"> - </div>
<div class="txt"> {{ myValue }} </div>
<div class="btn-minus" (click)="add(-1)"> + </div>


In my component .ts file I have:



add(num) {
this.myValue +=num;
this.update(); // async function which will send PUT request
}


The this.update() function put myValue to proper field in big JSON object and send it to server.



Problem: When user click 10x in short period of time on button plus/minus, then request will be send 10 times. But I wanna to send request only once - 0.5 sec after last click. How to do it?










share|improve this question





























    0















    In my template I have field and two buttons:



    <div class="btn-plus" (click)="add(1)"> - </div>
    <div class="txt"> {{ myValue }} </div>
    <div class="btn-minus" (click)="add(-1)"> + </div>


    In my component .ts file I have:



    add(num) {
    this.myValue +=num;
    this.update(); // async function which will send PUT request
    }


    The this.update() function put myValue to proper field in big JSON object and send it to server.



    Problem: When user click 10x in short period of time on button plus/minus, then request will be send 10 times. But I wanna to send request only once - 0.5 sec after last click. How to do it?










    share|improve this question



























      0












      0








      0








      In my template I have field and two buttons:



      <div class="btn-plus" (click)="add(1)"> - </div>
      <div class="txt"> {{ myValue }} </div>
      <div class="btn-minus" (click)="add(-1)"> + </div>


      In my component .ts file I have:



      add(num) {
      this.myValue +=num;
      this.update(); // async function which will send PUT request
      }


      The this.update() function put myValue to proper field in big JSON object and send it to server.



      Problem: When user click 10x in short period of time on button plus/minus, then request will be send 10 times. But I wanna to send request only once - 0.5 sec after last click. How to do it?










      share|improve this question
















      In my template I have field and two buttons:



      <div class="btn-plus" (click)="add(1)"> - </div>
      <div class="txt"> {{ myValue }} </div>
      <div class="btn-minus" (click)="add(-1)"> + </div>


      In my component .ts file I have:



      add(num) {
      this.myValue +=num;
      this.update(); // async function which will send PUT request
      }


      The this.update() function put myValue to proper field in big JSON object and send it to server.



      Problem: When user click 10x in short period of time on button plus/minus, then request will be send 10 times. But I wanna to send request only once - 0.5 sec after last click. How to do it?







      angular typescript rxjs debounce






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 15 '18 at 12:42







      Kamil Kiełczewski

















      asked Nov 15 '18 at 12:32









      Kamil KiełczewskiKamil Kiełczewski

      12.6k86896




      12.6k86896
























          2 Answers
          2






          active

          oldest

          votes


















          3














          Use the takeUntil operator :



          export class AppComponent  {
          name = 'Angular';

          calls = new Subject();

          service = {
          getData: () => of({ id: 1 }).pipe(delay(500)),
          };

          click() {
          this.calls.next(true);
          this.service.getData().pipe(
          takeUntil(this.calls),
          ).subscribe(res => console.log(res));
          }
          }


          Stackblitz (open your console to check the logs)






          share|improve this answer
























          • In Stackblitz every time when I click on "Simulate HTTP call" button i get immediately error "ERROR TypeError: _co.simulate is not a function"

            – Kamil Kiełczewski
            Nov 15 '18 at 13:00













          • Damn it, I renamed it --' Try again !

            – trichetriche
            Nov 15 '18 at 13:01











          • Now is ok. I give +1 (~15 min ago), however this solution in not so reusable as Cory Rylan directive so I will not "check" it as best answer. But thank you for your answer

            – Kamil Kiełczewski
            Nov 15 '18 at 13:05













          • I'm not here to code a directive but to give you another lead, feel free to create a directive from that ! But I understand your position and I'm totally fine with it, even though the directive is way more complicated to use than that.

            – trichetriche
            Nov 15 '18 at 13:07



















          0














          This is answer partially I found in internet, but I open to better solutions (or improve to below solution(directive)):



          In internet I found appDebounceClick directive which helps me in following way:



          I remove update from add in .ts file:



          add(num) {
          this.myValue +=num;
          }


          And change template in following way:



          <div 
          appDebounceClick
          (debounceClick)="update()"
          (click)="add(1)"
          class="btn-plus"
          > -
          </div>
          <div class="txt"> {{ myValue }} </div>
          <!-- similar for btn-minus -->


          BONUS



          Directive appDebounceClick written by Cory Rylan (I put code here in case if link will stop working in future):



          import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
          import { Subject } from 'rxjs/Subject';
          import { Subscription } from 'rxjs/Subscription';
          import { debounceTime } from 'rxjs/operators';

          @Directive({
          selector: '[appDebounceClick]'
          })
          export class DebounceClickDirective implements OnInit, OnDestroy {
          @Input() debounceTime = 500;
          @Output() debounceClick = new EventEmitter();
          private clicks = new Subject();
          private subscription: Subscription;

          constructor() { }

          ngOnInit() {
          this.subscription = this.clicks.pipe(
          debounceTime(this.debounceTime)
          ).subscribe(e => this.debounceClick.emit(e));
          }

          ngOnDestroy() {
          this.subscription.unsubscribe();
          }

          @HostListener('click', ['$event'])
          clickEvent(event) {
          event.preventDefault();
          event.stopPropagation();
          this.clicks.next(event);
          }
          }





          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53319597%2fangular-click-debounce%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            3














            Use the takeUntil operator :



            export class AppComponent  {
            name = 'Angular';

            calls = new Subject();

            service = {
            getData: () => of({ id: 1 }).pipe(delay(500)),
            };

            click() {
            this.calls.next(true);
            this.service.getData().pipe(
            takeUntil(this.calls),
            ).subscribe(res => console.log(res));
            }
            }


            Stackblitz (open your console to check the logs)






            share|improve this answer
























            • In Stackblitz every time when I click on "Simulate HTTP call" button i get immediately error "ERROR TypeError: _co.simulate is not a function"

              – Kamil Kiełczewski
              Nov 15 '18 at 13:00













            • Damn it, I renamed it --' Try again !

              – trichetriche
              Nov 15 '18 at 13:01











            • Now is ok. I give +1 (~15 min ago), however this solution in not so reusable as Cory Rylan directive so I will not "check" it as best answer. But thank you for your answer

              – Kamil Kiełczewski
              Nov 15 '18 at 13:05













            • I'm not here to code a directive but to give you another lead, feel free to create a directive from that ! But I understand your position and I'm totally fine with it, even though the directive is way more complicated to use than that.

              – trichetriche
              Nov 15 '18 at 13:07
















            3














            Use the takeUntil operator :



            export class AppComponent  {
            name = 'Angular';

            calls = new Subject();

            service = {
            getData: () => of({ id: 1 }).pipe(delay(500)),
            };

            click() {
            this.calls.next(true);
            this.service.getData().pipe(
            takeUntil(this.calls),
            ).subscribe(res => console.log(res));
            }
            }


            Stackblitz (open your console to check the logs)






            share|improve this answer
























            • In Stackblitz every time when I click on "Simulate HTTP call" button i get immediately error "ERROR TypeError: _co.simulate is not a function"

              – Kamil Kiełczewski
              Nov 15 '18 at 13:00













            • Damn it, I renamed it --' Try again !

              – trichetriche
              Nov 15 '18 at 13:01











            • Now is ok. I give +1 (~15 min ago), however this solution in not so reusable as Cory Rylan directive so I will not "check" it as best answer. But thank you for your answer

              – Kamil Kiełczewski
              Nov 15 '18 at 13:05













            • I'm not here to code a directive but to give you another lead, feel free to create a directive from that ! But I understand your position and I'm totally fine with it, even though the directive is way more complicated to use than that.

              – trichetriche
              Nov 15 '18 at 13:07














            3












            3








            3







            Use the takeUntil operator :



            export class AppComponent  {
            name = 'Angular';

            calls = new Subject();

            service = {
            getData: () => of({ id: 1 }).pipe(delay(500)),
            };

            click() {
            this.calls.next(true);
            this.service.getData().pipe(
            takeUntil(this.calls),
            ).subscribe(res => console.log(res));
            }
            }


            Stackblitz (open your console to check the logs)






            share|improve this answer













            Use the takeUntil operator :



            export class AppComponent  {
            name = 'Angular';

            calls = new Subject();

            service = {
            getData: () => of({ id: 1 }).pipe(delay(500)),
            };

            click() {
            this.calls.next(true);
            this.service.getData().pipe(
            takeUntil(this.calls),
            ).subscribe(res => console.log(res));
            }
            }


            Stackblitz (open your console to check the logs)







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 15 '18 at 12:44









            trichetrichetrichetriche

            28.3k42560




            28.3k42560













            • In Stackblitz every time when I click on "Simulate HTTP call" button i get immediately error "ERROR TypeError: _co.simulate is not a function"

              – Kamil Kiełczewski
              Nov 15 '18 at 13:00













            • Damn it, I renamed it --' Try again !

              – trichetriche
              Nov 15 '18 at 13:01











            • Now is ok. I give +1 (~15 min ago), however this solution in not so reusable as Cory Rylan directive so I will not "check" it as best answer. But thank you for your answer

              – Kamil Kiełczewski
              Nov 15 '18 at 13:05













            • I'm not here to code a directive but to give you another lead, feel free to create a directive from that ! But I understand your position and I'm totally fine with it, even though the directive is way more complicated to use than that.

              – trichetriche
              Nov 15 '18 at 13:07



















            • In Stackblitz every time when I click on "Simulate HTTP call" button i get immediately error "ERROR TypeError: _co.simulate is not a function"

              – Kamil Kiełczewski
              Nov 15 '18 at 13:00













            • Damn it, I renamed it --' Try again !

              – trichetriche
              Nov 15 '18 at 13:01











            • Now is ok. I give +1 (~15 min ago), however this solution in not so reusable as Cory Rylan directive so I will not "check" it as best answer. But thank you for your answer

              – Kamil Kiełczewski
              Nov 15 '18 at 13:05













            • I'm not here to code a directive but to give you another lead, feel free to create a directive from that ! But I understand your position and I'm totally fine with it, even though the directive is way more complicated to use than that.

              – trichetriche
              Nov 15 '18 at 13:07

















            In Stackblitz every time when I click on "Simulate HTTP call" button i get immediately error "ERROR TypeError: _co.simulate is not a function"

            – Kamil Kiełczewski
            Nov 15 '18 at 13:00







            In Stackblitz every time when I click on "Simulate HTTP call" button i get immediately error "ERROR TypeError: _co.simulate is not a function"

            – Kamil Kiełczewski
            Nov 15 '18 at 13:00















            Damn it, I renamed it --' Try again !

            – trichetriche
            Nov 15 '18 at 13:01





            Damn it, I renamed it --' Try again !

            – trichetriche
            Nov 15 '18 at 13:01













            Now is ok. I give +1 (~15 min ago), however this solution in not so reusable as Cory Rylan directive so I will not "check" it as best answer. But thank you for your answer

            – Kamil Kiełczewski
            Nov 15 '18 at 13:05







            Now is ok. I give +1 (~15 min ago), however this solution in not so reusable as Cory Rylan directive so I will not "check" it as best answer. But thank you for your answer

            – Kamil Kiełczewski
            Nov 15 '18 at 13:05















            I'm not here to code a directive but to give you another lead, feel free to create a directive from that ! But I understand your position and I'm totally fine with it, even though the directive is way more complicated to use than that.

            – trichetriche
            Nov 15 '18 at 13:07





            I'm not here to code a directive but to give you another lead, feel free to create a directive from that ! But I understand your position and I'm totally fine with it, even though the directive is way more complicated to use than that.

            – trichetriche
            Nov 15 '18 at 13:07













            0














            This is answer partially I found in internet, but I open to better solutions (or improve to below solution(directive)):



            In internet I found appDebounceClick directive which helps me in following way:



            I remove update from add in .ts file:



            add(num) {
            this.myValue +=num;
            }


            And change template in following way:



            <div 
            appDebounceClick
            (debounceClick)="update()"
            (click)="add(1)"
            class="btn-plus"
            > -
            </div>
            <div class="txt"> {{ myValue }} </div>
            <!-- similar for btn-minus -->


            BONUS



            Directive appDebounceClick written by Cory Rylan (I put code here in case if link will stop working in future):



            import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
            import { Subject } from 'rxjs/Subject';
            import { Subscription } from 'rxjs/Subscription';
            import { debounceTime } from 'rxjs/operators';

            @Directive({
            selector: '[appDebounceClick]'
            })
            export class DebounceClickDirective implements OnInit, OnDestroy {
            @Input() debounceTime = 500;
            @Output() debounceClick = new EventEmitter();
            private clicks = new Subject();
            private subscription: Subscription;

            constructor() { }

            ngOnInit() {
            this.subscription = this.clicks.pipe(
            debounceTime(this.debounceTime)
            ).subscribe(e => this.debounceClick.emit(e));
            }

            ngOnDestroy() {
            this.subscription.unsubscribe();
            }

            @HostListener('click', ['$event'])
            clickEvent(event) {
            event.preventDefault();
            event.stopPropagation();
            this.clicks.next(event);
            }
            }





            share|improve this answer






























              0














              This is answer partially I found in internet, but I open to better solutions (or improve to below solution(directive)):



              In internet I found appDebounceClick directive which helps me in following way:



              I remove update from add in .ts file:



              add(num) {
              this.myValue +=num;
              }


              And change template in following way:



              <div 
              appDebounceClick
              (debounceClick)="update()"
              (click)="add(1)"
              class="btn-plus"
              > -
              </div>
              <div class="txt"> {{ myValue }} </div>
              <!-- similar for btn-minus -->


              BONUS



              Directive appDebounceClick written by Cory Rylan (I put code here in case if link will stop working in future):



              import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
              import { Subject } from 'rxjs/Subject';
              import { Subscription } from 'rxjs/Subscription';
              import { debounceTime } from 'rxjs/operators';

              @Directive({
              selector: '[appDebounceClick]'
              })
              export class DebounceClickDirective implements OnInit, OnDestroy {
              @Input() debounceTime = 500;
              @Output() debounceClick = new EventEmitter();
              private clicks = new Subject();
              private subscription: Subscription;

              constructor() { }

              ngOnInit() {
              this.subscription = this.clicks.pipe(
              debounceTime(this.debounceTime)
              ).subscribe(e => this.debounceClick.emit(e));
              }

              ngOnDestroy() {
              this.subscription.unsubscribe();
              }

              @HostListener('click', ['$event'])
              clickEvent(event) {
              event.preventDefault();
              event.stopPropagation();
              this.clicks.next(event);
              }
              }





              share|improve this answer




























                0












                0








                0







                This is answer partially I found in internet, but I open to better solutions (or improve to below solution(directive)):



                In internet I found appDebounceClick directive which helps me in following way:



                I remove update from add in .ts file:



                add(num) {
                this.myValue +=num;
                }


                And change template in following way:



                <div 
                appDebounceClick
                (debounceClick)="update()"
                (click)="add(1)"
                class="btn-plus"
                > -
                </div>
                <div class="txt"> {{ myValue }} </div>
                <!-- similar for btn-minus -->


                BONUS



                Directive appDebounceClick written by Cory Rylan (I put code here in case if link will stop working in future):



                import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
                import { Subject } from 'rxjs/Subject';
                import { Subscription } from 'rxjs/Subscription';
                import { debounceTime } from 'rxjs/operators';

                @Directive({
                selector: '[appDebounceClick]'
                })
                export class DebounceClickDirective implements OnInit, OnDestroy {
                @Input() debounceTime = 500;
                @Output() debounceClick = new EventEmitter();
                private clicks = new Subject();
                private subscription: Subscription;

                constructor() { }

                ngOnInit() {
                this.subscription = this.clicks.pipe(
                debounceTime(this.debounceTime)
                ).subscribe(e => this.debounceClick.emit(e));
                }

                ngOnDestroy() {
                this.subscription.unsubscribe();
                }

                @HostListener('click', ['$event'])
                clickEvent(event) {
                event.preventDefault();
                event.stopPropagation();
                this.clicks.next(event);
                }
                }





                share|improve this answer















                This is answer partially I found in internet, but I open to better solutions (or improve to below solution(directive)):



                In internet I found appDebounceClick directive which helps me in following way:



                I remove update from add in .ts file:



                add(num) {
                this.myValue +=num;
                }


                And change template in following way:



                <div 
                appDebounceClick
                (debounceClick)="update()"
                (click)="add(1)"
                class="btn-plus"
                > -
                </div>
                <div class="txt"> {{ myValue }} </div>
                <!-- similar for btn-minus -->


                BONUS



                Directive appDebounceClick written by Cory Rylan (I put code here in case if link will stop working in future):



                import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
                import { Subject } from 'rxjs/Subject';
                import { Subscription } from 'rxjs/Subscription';
                import { debounceTime } from 'rxjs/operators';

                @Directive({
                selector: '[appDebounceClick]'
                })
                export class DebounceClickDirective implements OnInit, OnDestroy {
                @Input() debounceTime = 500;
                @Output() debounceClick = new EventEmitter();
                private clicks = new Subject();
                private subscription: Subscription;

                constructor() { }

                ngOnInit() {
                this.subscription = this.clicks.pipe(
                debounceTime(this.debounceTime)
                ).subscribe(e => this.debounceClick.emit(e));
                }

                ngOnDestroy() {
                this.subscription.unsubscribe();
                }

                @HostListener('click', ['$event'])
                clickEvent(event) {
                event.preventDefault();
                event.stopPropagation();
                this.clicks.next(event);
                }
                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Nov 15 '18 at 13:16

























                answered Nov 15 '18 at 12:32









                Kamil KiełczewskiKamil Kiełczewski

                12.6k86896




                12.6k86896






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53319597%2fangular-click-debounce%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Bressuire

                    Vorschmack

                    Quarantine