2017-05-28 27 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