为什么投票选项未正确预选?

时间:2017-05-28 15:44:32

标签: node.js mongodb angular express vote

您需要通过身份验证才能对投票进行投票。投票时,有两个问题:

  1. 您可以无限次地投票,直到您离开或重新加载页面

  2. 当您重新加载页面时,您最终无法进行投票,但是您没有预先选择投票选项,而是始终预选的第二个选项。

  3. 应该发生什么:

    注册/登录,然后投票。您点击某个选项时,您所做的投票投票选择已被锁定,您无法对该投票进行更多投票。

    我的当前代码的流程如何运作:

    当用户点击某个选项时,计数器会增加,然后投票会保存在推送到数据库中User对象的数组中。

    当组件加载时,当前登录用户的投票数据库数据将通过本地ngOninit()变量中的votes方法保存,然后用于检查用户已经进行的轮询投票和他做了什么投票。问题是,如果事实并非如此,则选择总是选择2。

    我理解为什么你可以多次投票直到页面重新加载,但我只是不知道如何在用户投票后,在客户端和后端立即锁定投票(如果用户阻止更多投票被注册)已投票通过投票。)

    至于为什么它已经是预选的第二选择,我不知道。

    CODE:

    HTML

    <div class="formWidth">
        <form (ngSubmit)="onSubmit(f)" #f="ngForm">
            <div class="form-group">
                <label class="inputTitle" for="title">Poll Title</label>
                <input
                        type="text"
                        id="title"
                        class="form-control"
                        [ngModel]="poll?.title"
                        name="title"
                        required maxlenth="30">
                <label class="inputTitle" for="choice1">Choice1</label>
                <input
                        type="text"
                        id="choice1"
                        class="form-control"
                        [ngModel]="poll?.choice1"
                        name="choice1"
                        required maxlenth="20">
                <label class="inputTitle" for="choice2">Choice2</label>
                <input
                        type="text"
                        id="choice2"
                        class="form-control"
                        [ngModel]="poll?.choice2"
                        name="choice2"
                        required maxlenth="20">
            </div>
            <button type="button" class="btn btn-danger" (click)="onClear(f)">Clear</button>
            <button class="btn btn-primary" type="submit">Save</button>
        </form>
    </div>
    

    COMPONENT

    export class PollComponent {
        @Input() poll: Poll;
    
        constructor(private pollService: PollService) {}
    
        votes: any;
    
        // Pie
        public pieChartLabels:string[] = [];
        public pieChartData:number[] = [];
        public pieChartType:string = 'pie';
        public pieChartOptions:any = {};
    
        ngOnInit() {
            var result1 = parseFloat(((this.poll.counter1/(this.poll.counter2+this.poll.counter1))*100).toFixed(2));
            var result2 = parseFloat(((this.poll.counter2/(this.poll.counter2+this.poll.counter1))*100).toFixed(2));
            this.pieChartData = [result1, result2];
            this.pieChartLabels = [this.poll.choice1, this.poll.choice2];
            this.pieChartType = 'pie';
            this.pieChartOptions  = {
                tooltips: {
                enabled: true,
                mode: 'single',
                    callbacks: {
                        label: function(tooltipItem, data) {
                            var allData = data.datasets[tooltipItem.datasetIndex].data;
                            var tooltipLabel = data.labels[tooltipItem.index];
                            var tooltipData = allData[tooltipItem.index];
                            return tooltipLabel + ": " + tooltipData + "%";
                        }
                    }
                }
            }
    
            this.pollService.voted(localStorage.getItem('userId')).subscribe(
                data => {
                    var result = JSON.parse(data);
                    this.votes = result.votes;
                },
                err => { console.log("NGONINIT ERROR: "+ err) },
                () => { }
            );
        }
    
        onEdit() {
            this.pollService.editPoll(this.poll);
        }
    
        onDelete() {
            this.pollService.deletePoll(this.poll)
                .subscribe(
                    result => console.log(result)
                );
        }
    
        onChoice1() {
          this.pollService.increaseCounter1(this.poll);
          this.onVote1();
          var result1 = parseFloat(((this.poll.counter1/(this.poll.counter2+this.poll.counter1))*100).toFixed(2));
          var result2 = parseFloat(((this.poll.counter2/(this.poll.counter2+this.poll.counter1))*100).toFixed(2));
          this.pieChartData = [result1, result2];
        }
    
        onChoice2() {
          this.pollService.increaseCounter2(this.poll);
          this.onVote2();
          var result1 = parseFloat(((this.poll.counter1/(this.poll.counter2+this.poll.counter1))*100).toFixed(2));
          var result2 = parseFloat(((this.poll.counter2/(this.poll.counter2+this.poll.counter1))*100).toFixed(2));
          this.pieChartData = [result1, result2];
        }
    
        onVote1() {
          this.pollService.voteOn(this.poll.pollID,  localStorage.getItem('userId'), 1);
        }
    
        onVote2() {
          this.pollService.voteOn(this.poll.pollID,  localStorage.getItem('userId'), 2);
        }
    
        belongsToUser() {
            return localStorage.getItem('userId') == this.poll.userId;
        }
    
        alreadyVotedFor(choice: number) {
          var result = "";
          if (this.votes) {
              for (var i = 0; i < this.votes.length; i ++) {
                  if (this.votes[i].pollID == this.poll.pollID) {
                      result = "disabled";
                      if (this.votes[i].choice == choice) {
                          result =  "selected";
                      }
                  }
              }
          }
          return result;
        }
    
            // events
        public chartClicked(e:any):void {
    
        }
    
        public chartHovered(e:any):void {
    
        }
    
    }
    

    服务

    updatePoll(poll: Poll) {
            const body = JSON.stringify(poll);
            const token = localStorage.getItem('token')
                ? localStorage.getItem('token')
                : '';
            const headers = new Headers({
              'Content-Type': 'application/json',
              'Authorization': 'Bearer '+token
            });
            return this.http.patch('https://voting-app-10.herokuapp.com/poll/' + poll.pollID, body, {headers: headers})
                .map((response: Response) => response.json())
                .catch((error: Response) => {
                    this.errorService.handleError(error.json());
                    return Observable.throw(error);
                });
        }
    
        increaseCounter1(poll: Poll) {
            poll.counter1++;
            const body = JSON.stringify(poll);
            const token = localStorage.getItem('token')
                ? localStorage.getItem('token')
                : '';
            const headers = new Headers({
              'Content-Type': 'application/json',
              'Authorization': 'Bearer '+token
            });
            this.http.patch('https://voting-app-10.herokuapp.com/poll/vote/' + poll.pollID, body, {headers: headers})
                .map((response: Response) => response.json())
                .catch((error: Response) => {
                    this.errorService.handleError(error.json());
                    return Observable.throw(error);
                })
                .subscribe();
        }
    
        increaseCounter2(poll: Poll) {
            poll.counter2++;
            const body = JSON.stringify(poll);
            const token = localStorage.getItem('token')
                ? localStorage.getItem('token')
                : '';
            const headers = new Headers({
              'Content-Type': 'application/json',
              'Authorization': 'Bearer '+token
            });
            return this.http.patch('https://voting-app-10.herokuapp.com/poll/vote/' + poll.pollID, body, {headers: headers})
                .map((response: Response) => response.json())
                .catch((error: Response) => {
                    this.errorService.handleError(error.json());
                    return Observable.throw(error);
                })
                .subscribe();
        }
    
        voteOn(pollID: string, userID: string, choice: number) {
          var user;
          this.http.get('https://voting-app-10.herokuapp.com/user/'+userID)
          .map(response => response.json())
          .subscribe(
                json => {
                  user = JSON.parse(json);
                  if (user.votes == undefined) {
                    user.votes = [{pollID, choice}];
                  } else {
                    user.votes.push({pollID, choice});
                  }
                  const body = user;
                  const token = localStorage.getItem('token')
                      ? localStorage.getItem('token')
                      : '';
                  const headers = new Headers({
                    'Content-Type': 'application/json',
                    'Authorization': 'Bearer '+token
                  });
                  return this.http.patch('https://voting-app-10.herokuapp.com/user/', body, {headers: headers})
                      .map((response: Response) => response.json())
                      .catch((error: Response) => {
                          this.errorService.handleError(error.json());
                          return Observable.throw(error);
                      })
                      .subscribe();
                }
           )
        }
    
        voted(userID: string) {
            const headers = new Headers({'Content-Type': 'application/json'});
            return this.http.get('https://voting-app-10.herokuapp.com/user/'+userID,{headers: headers})
                            .map(response => response.json())
                            .catch((error: Response) => {
                                this.errorService.handleError(error.json());
                                return Observable.throw(error);
                            });
        }
    

    路线(后退)

    router.patch('/vote/:id', function (req, res, next) {
        var decoded = jwt.decode(getToken(req));
        Poll.findById(req.params.id, function (err, poll) {
            if (err) {
                return res.status(500).json({
                    title: 'An error occurred',
                    error: err
                });
            }
            if (!poll) {
                return res.status(500).json({
                    title: 'No Poll Found!',
                    error: {poll: 'Poll not found'}
                });
            }
            poll.title = req.body.title;
            poll.choice1 = req.body.choice1;
            poll.choice2 = req.body.choice2;
            poll.counter1 = req.body.counter1;
            poll.counter2 = req.body.counter2;
    
            poll.save(function (err, result) {
                if (err) {
                    return res.status(500).json({
                        title: 'An error occurred',
                        error: err
                    });
                }
                res.status(200).json({
                    poll: 'Updated poll',
                    obj: result
                });
            });
        });
    });
    
    router.patch('/:id', function (req, res, next) {
        var decoded = jwt.decode(getToken(req));
        Poll.findById(req.params.id, function (err, poll) {
            if (err) {
                return res.status(500).json({
                    title: 'An error occurred',
                    error: err
                });
            }
            if (!poll) {
                return res.status(500).json({
                    title: 'No Poll Found!',
                    error: {poll: 'Poll not found'}
                });
            }
            if (poll.user != decoded.user._id) {
                return res.status(401).json({
                    title: 'Not Authenticated',
                    error: {poll: 'Users do not match'}
                });
            }
            poll.title = req.body.title;
            poll.choice1 = req.body.choice1;
            poll.choice2 = req.body.choice2;
            poll.counter1 = req.body.counter1;
            poll.counter2 = req.body.counter2;
    
            poll.save(function (err, result) {
                if (err) {
                    return res.status(500).json({
                        title: 'An error occurred',
                        error: err
                    });
                }
                res.status(200).json({
                    poll: 'Updated poll',
                    obj: result
                });
            });
        });
    });
    

1 个答案:

答案 0 :(得分:1)

好的,首先你的单选按钮不会被禁用,因为你在保存投票后没有更新poll.component.ts中的投票数组。

我不确定这是不是一个好的解决方案:

poll.service.ts

voteOn(pollID: string, userID: string, choice: number) {
    var user;
    return new Promise((resolve) => { //Create a new promise to wrap the Subscriptions
    this.http.get('http://localhost:3000/user/' + userID)
        .map(response => response.json())
        .subscribe(
        json => {
            user = JSON.parse(json);
            if (user.votes == undefined) {

            ...

                .catch((error: Response) => {
                    this.errorService.handleError(error.json());
                    return Observable.throw(error);
                }).subscribe(() => {
                    resolve(user.votes); // <- Resolve your promise
                })
        }
        )
        });
}

在您的poll.component.ts

voteOn(...).then((votes) => {
    this.votes = votes; // To update your votes array
    this.updateVote();
})

我不建议在绑定中调用函数,因为它经常调用函数来“检测更改”,就像在组件中一样。 所以我会按照以下方式更改代码:

poll.component.ts

vote:any //Added to your poll component


updateVote() {
    this.vote = this.votes.find((vote) => {
        return vote.pollID === this.poll.pollID;
    });
}

您需要在ngOnInit方法中调用此方法:

    this.pollService.voted(localStorage.getItem('userId')).subscribe(
        data => {
            var result = JSON.parse(data);
            this.votes = result.votes;
            this.updateVote(); // <- To select the vote of this poll
        },
        err => { console.log("NGONINIT ERROR: " + err) },
        () => { }
    );

在您的poll.component.html

    <fieldset [disabled]="vote">
      {{ poll.counter1 }} votes <input type="radio" id="{{ poll.choice1 }}" name="my_radio" value="{{ poll.choice1 }}" (click)="onChoice1(form)" [checked]="vote?.choice == 1">  {{ poll.choice1 }}
      <br>
      {{ poll.counter2 }} votes <input type="radio" id="{{ poll.choice2  }}" name="my_radio" value="{{ poll.choice2 }}" (click)="onChoice2(form)" [checked]="vote?.choice == 2">  {{ poll.choice2 }}
    </fieldset>

但如果您不想以这种方式更改代码,请告诉我,我可以提供另一种解决方案。

相关问题