+
diff --git a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts
index f5b0fb3cc..e90c4da91 100644
--- a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts
+++ b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts
@@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core';
-import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material';
import { Title } from '@angular/platform-browser';
@@ -10,7 +10,7 @@ import { AssignmentPollRepositoryService } from 'app/core/repositories/assignmen
import { AssignmentVoteRepositoryService } from 'app/core/repositories/assignments/assignment-vote-repository.service';
import { VotingService } from 'app/core/ui-services/voting.service';
import { AssignmentPollMethods } from 'app/shared/models/assignments/assignment-poll';
-import { VoteValueVerbose } from 'app/shared/models/poll/base-vote';
+import { PollType } from 'app/shared/models/poll/base-poll';
import { BasePollVoteComponent } from 'app/site/polls/components/base-poll-vote.component';
import { ViewAssignmentPoll } from '../../models/view-assignment-poll';
import { ViewAssignmentVote } from '../../models/view-assignment-vote';
@@ -22,11 +22,12 @@ import { ViewAssignmentVote } from '../../models/view-assignment-vote';
})
export class AssignmentPollVoteComponent extends BasePollVoteComponent implements OnInit {
public pollMethods = AssignmentPollMethods;
+ public PollType = PollType;
public voteForm: FormGroup;
/** holds the currently saved votes */
- public currentVotes: { [key: number]: string | number | null } = {};
+ public currentVotes: { [key: number]: string | null; global?: string } = {};
private votes: ViewAssignmentVote[];
@@ -57,30 +58,114 @@ export class AssignmentPollVoteComponent extends BasePollVoteComponent vote.option.poll_id === this.poll.id && vote.user_id === this.user.id
);
- this.voteForm = this.formBuilder.group(
- this.poll.options.reduce((obj, option) => {
- obj[option.id] = ['', [Validators.required]];
- return obj;
- }, {})
- );
+ this.voteForm = this.formBuilder.group({
+ votes: this.formBuilder.group(
+ this.poll.options.mapToObject(option => ({ [option.id]: ['', [Validators.required]] }))
+ )
+ });
+ if (
+ this.poll.pollmethod === AssignmentPollMethods.Votes &&
+ (this.poll.global_no || this.poll.global_abstain)
+ ) {
+ this.voteForm.addControl('global', new FormControl('', Validators.required));
+ }
+
for (const option of this.poll.options) {
- const curr_vote = filtered.find(vote => vote.option.id === option.id);
- this.currentVotes[option.user_id] = curr_vote
- ? this.poll.pollmethod === AssignmentPollMethods.Votes
- ? curr_vote.weight
- : curr_vote.value
- : null;
- this.voteForm.get(option.id.toString()).setValue(this.currentVotes[option.user_id]);
+ let curr_vote = filtered.find(vote => vote.option.id === option.id);
+ if (this.poll.pollmethod === AssignmentPollMethods.Votes && curr_vote) {
+ if (curr_vote.value !== 'Y') {
+ this.currentVotes.global = curr_vote.valueVerbose;
+ this.voteForm.controls.global.setValue(curr_vote.value);
+ curr_vote = null;
+ } else {
+ this.currentVotes.global = null;
+ }
+ }
+ this.currentVotes[option.user_id] = curr_vote && curr_vote.valueVerbose;
+ this.voteForm.get(['votes', option.id]).setValue(curr_vote && curr_vote.value);
+ }
+
+ if (this.poll.pollmethod === AssignmentPollMethods.Votes) {
+ this.voteForm.controls.votes.valueChanges.subscribe(value => {
+ if (Object.values(value).some(vote => vote)) {
+ const ctrl = this.voteForm.controls.global;
+ if (ctrl) {
+ ctrl.reset();
+ }
+ this.saveVotesIfNamed();
+ }
+ });
+
+ this.voteForm.controls.global.valueChanges.subscribe(value => {
+ if (value) {
+ this.voteForm.controls.votes.reset();
+ this.saveVotesIfNamed();
+ }
+ });
}
}
}
- public saveVotes(): void {
- this.pollRepo.vote(this.voteForm.value, this.poll.id).catch(this.raiseError);
+ private saveVotesIfNamed(): void {
+ if (this.poll.type === PollType.Named && !this.isSaveButtonDisabled()) {
+ this.saveVotes();
+ }
}
- public getCurrentVoteVerbose(user_id: number): string {
- const curr_vote = this.currentVotes[user_id];
- return this.poll.pollmethod === AssignmentPollMethods.Votes ? curr_vote : VoteValueVerbose[curr_vote];
+ public saveVotes(): void {
+ let values = this.voteForm.value.votes;
+ // convert Y to 1 and null to 0 for votes method
+ if (this.poll.pollmethod === this.pollMethods.Votes) {
+ if (this.voteForm.value.global) {
+ values = JSON.stringify(this.voteForm.value.global);
+ } else {
+ this.poll.options.forEach(option => {
+ values[option.id] = this.voteForm.value.votes[option.id] === 'Y' ? 1 : 0;
+ });
+ }
+ }
+ this.pollRepo.vote(values, this.poll.id).catch(this.raiseError);
+ }
+
+ public isSaveButtonDisabled(): boolean {
+ return (
+ !this.voteForm ||
+ this.voteForm.pristine ||
+ (this.poll.pollmethod === AssignmentPollMethods.Votes
+ ? !this.getAllFormControls().some(control => control.valid)
+ : this.voteForm.invalid)
+ );
+ }
+
+ public getVotesCount(): number {
+ return Object.values(this.voteForm.value.votes).filter(vote => vote).length;
+ }
+
+ private getAllFormControls(): AbstractControl[] {
+ if (this.voteForm) {
+ const votesFormGroup = this.voteForm.controls.votes as FormGroup;
+ return [...Object.values(votesFormGroup.controls), this.voteForm.controls.global];
+ } else {
+ return [];
+ }
+ }
+
+ public yesButtonClicked($event: MouseEvent, optionId: string): void {
+ if (this.poll.pollmethod === AssignmentPollMethods.Votes) {
+ // check current value (before click)
+ if (this.voteForm.value.votes[optionId] === 'Y') {
+ // this handler is executed before the mat-radio-button handler, so we have to set a timeout or else the other handler will just set the value again
+ setTimeout(() => {
+ this.voteForm.get(['votes', optionId]).setValue(null);
+ this.voteForm.markAsDirty();
+ this.saveVotesIfNamed();
+ });
+ } else {
+ // check if by clicking this button, the amount of votes would succeed the permitted amount
+ if (this.getVotesCount() >= this.poll.votes_amount) {
+ $event.preventDefault();
+ }
+ }
+ }
}
}
diff --git a/client/src/app/site/polls/components/poll-form/poll-form.component.html b/client/src/app/site/polls/components/poll-form/poll-form.component.html
index 3f8213039..e6966d0dd 100644
--- a/client/src/app/site/polls/components/poll-form/poll-form.component.html
+++ b/client/src/app/site/polls/components/poll-form/poll-form.component.html
@@ -17,9 +17,9 @@
diff --git a/client/src/app/site/polls/components/poll-form/poll-form.component.ts b/client/src/app/site/polls/components/poll-form/poll-form.component.ts
index d975844da..fbc99ccca 100644
--- a/client/src/app/site/polls/components/poll-form/poll-form.component.ts
+++ b/client/src/app/site/polls/components/poll-form/poll-form.component.ts
@@ -8,10 +8,13 @@ import { Observable } from 'rxjs';
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
import { PercentBase } from 'app/shared/models/poll/base-poll';
+import { PollType } from 'app/shared/models/poll/base-poll';
+import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
import { BaseViewComponent } from 'app/site/base/base-view';
import {
MajorityMethodVerbose,
PercentBaseVerbose,
+ PollPropertyVerbose,
PollTypeVerbose,
ViewBasePoll
} from 'app/site/polls/models/view-base-poll';
@@ -29,6 +32,9 @@ export class PollFormComponent extends BaseViewComponent implements OnInit {
*/
public contentForm: FormGroup;
+ public PollType = PollType;
+ public PollPropertyVerbose = PollPropertyVerbose;
+
/**
* The different methods for this poll.
*/
@@ -92,6 +98,11 @@ export class PollFormComponent extends BaseViewComponent implements OnInit {
public ngOnInit(): void {
this.groupObservable = this.groupRepo.getViewModelListObservable();
+ const cast =