2017-05-28 57 views
-1

您需要通过身份验证才能对投票进行投票。当您在投票方式行使表决权,有2个问题:为什么投票选项未正确预选?

  1. 当你重新加载页面你可以直到你离开投的无数次或重新载入页面

  2. ,你终于从防止投票,而不是让您选择预选的选项,它始终是预选的第二个选项。


希望发生的事情:

注册/登录,然后在投票方式行使表决权。当您点击某个选项时,您所做的投票选择被锁定,您无法在该投票中投票。


HOW我的当前代码的流程WORKS:

当用户点击一个选项,该计数器被增加,然后表决被保存在该被推到用户对象的阵列在数据库中。

当部件载荷,选票在当前登录用户的数据库中的数据通过ngOninit()方法保存在本地votes变量,然后将其用于检查其调查用户已经投票,他做了什么票里面。问题在于,如果事实并非如此,那么选择总是选择2。

我明白你为什么可以多次投票直到页面重新载入,但我不知道如何在用户投票后在客户端和后端立即锁定投票(防止更多投票被注册为if用户已投票投票)。

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


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 { 

    } 

} 

SERVI CE

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); 
         }); 
    } 

ROUTE(BACKEND)

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

请不要回滚有效更正的帖子。问题不应该包含任何meta cruft。如果你想把这个政策讨论到[meta]。 –

回答

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> 

但是如果你不想以这种方式改变你的代码,请告诉我,所以我可以提供另一种解决方案。

+0

按照承诺,当SO让我(在不到48小时)内,我会给予你50分的奖励。谢谢你的回答! – Coder1000