Angular2 and Html forms - issue with two way databinding blank, required, selected - html

I am generating an array based on a number that is input by the user:
<div class="form-group">
<input type="number"
class="form-control"
id="numPeople"
[(ngModel)]="numPeople"
name="numPeople"
required>
</div>
With this number, I generate an array of [['name', 'gender'],*number...]. I am then trying to use ngForm to bind directly into this array and I wanted to have a gender set as default but having trouble with it in two ways:
1) is not working so I can't have a default value in the select, and required is not forcing an entry so you can press submit without selecting an option even with the required flag set.
2) I am getting this error when I delete the placeholder text being read in from 2 way databinding into the input box, and if I try insert a blank string, i.e. by putting '' into the array on the backend: [ '', '' ]
EXCEPTION: Error in ./SellTicketComponent class SellTicketComponent -
inline template:373:28 caused by: If ngModel is used within a form
tag, either the name attribute must be set or the form
control must be defined as 'standalone' in ngModelOptions.
Example 1: <input [(ngModel)]="person.firstName" name="first">
Example 2: <input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}"> ErrorHandler.handleError #
error_handler.js:54 next # application_ref.js:359 schedulerFn #
async.js:93 SafeSubscriber.__tryOrUnsub # Subscriber.js:223
SafeSubscriber.next # Subscriber.js:172 Subscriber._next #
Subscriber.js:125 Subscriber.next # Subscriber.js:89 Subject.next #
Subject.js:55 EventEmitter.emit # async.js:79 NgZone.triggerError #
ng_zone.js:331 onHandleError # ng_zone.js:292 ZoneDelegate.handleError
# zone.js:246 Zone.runTask # zone.js:154 ZoneTask.invoke # zone.js:345
error_handler.js:56 ORIGINAL EXCEPTION: If ngModel is used within a
form tag, either the name attribute must be set or the form
control must be defined as 'standalone' in ngModelOptions.
Example 1: <input [(ngModel)]="person.firstName" name="first">
Example 2: <input [(ngModel)]="person.firstName" [ngModelOptions]="{standalone: true}">
This is the code:
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
<label> Enter the details of all your plus ones for the guest list: </label>
<br>
<div *ngFor="let guest of guests; let i = index;">
<label> Enter First and Last Name:</label>
<div class="form-group">
<input type="text"
class="form-control"
id="{{guest[0]}}"
[(ngModel)]="guest[0]"
name="{{guest[0]}}"
required>
</div>
<div class="form-group">
<label> Enter Gender: </label>
<select
class="form-control"
id="{{i}}"
name="{{i}}"
[(ngModel)]="guest[1]"
required>
<option value="female" selected>
female
</option>
<option value="male">
male
</option>
</select>
</div>
</div>
</form>

Not really knowing how you generate your guests and how they look like.... since you seem to use [(ngModel)]="guests[0]", I would assume you'd want to use [(ngModel)]="guests[i]" instead. Here is an example using the latter.
If you want to use two way binding for the guest, when you generate the guests, you can preset the gender value to female, so that it will be preselected in the dropdown, e.g:
this.guests.push({name:'',gender:'female'}, {name:'',gender:'female'});
If you don't need the two way binding for guests, you can use e.g [(ngModel)]="selected", where in your component you have declared selected: string = 'female'. That will work as well.
So all in all your form could look like this:¨
<button (click)="generate()">Generate 2 Guests</button> <!-- dummy button -->
<form (ngSubmit)="onSubmit(f.value)" #f="ngForm">
<label> Enter the details of all your plus ones for the guest list: </label>
<div *ngFor="let guest of guests; let i = index;">
<label> Enter First and Last Name:</label>
<div>
<input type="text" name="guest{{i}}" [(ngModel)]="guests[i].name" required>
</div>
<div>
<label> Enter Gender: </label>
<select name="gender{{i}}" [(ngModel)]="guests[i].gender" required>
<option value="female">female</option>
<option value="male">male</option>
</select>
</div>
</div>
<button type="submit">Submit</button>
</form>
This will check the validity of the fields. Here of course user can enter just white spaces, so you'd need to check that as well.
Here's a Demo Plunker (which does not check white spaces)
Hope this helps! :)

Related

Freemarker how to select checkboxes on UI send by backend?

Have following data passed from backend:
ALL_CONFIGS: {callDigitalIo=true, controllerId=1, numberPlatesHashSalt=..., numberPlatesShouldBeHashed=false, parkingStatusShouldBeChecked=true}
Where boolean params should be displayed like input element with type=checkbox.
Here is how I handle it on UI page (.ftl):
<div>
<label class="col-form-label">
Parking Status Should Be Checked:
<input type="checkbox" class="form-check-input ml-2"
id="parkingStatusShouldBeChecked" name="parkingStatusShouldBeChecked"
<#if parkingStatusShouldBeChecked??>checked="checked"</#if>
/>
</label>
</div>
However, checkboxes are all selected:
Number Plates Should be Hashed should not be selected.
How to select only true variables?
After huge research I found solution for this issue:
<div>
<label class="col-form-label">
Parking Status Should Be Checked:
<input type="checkbox" class="form-check-input ml-2"
id="parkingStatusShouldBeChecked"
<#if parkingStatusShouldBeChecked == "true">checked</#if>
/>
</label>
</div>
It works fine.
Assuming that parkingStatusShouldBeChecked is a boolean, this way works too:
<input type="checkbox" class="form-check-input ml-2"
id="parkingStatusShouldBeChecked" name="parkingStatusShouldBeChecked"
${parkingStatusShouldBeChecked?string('checked','')} />
The first parameter is the "true" expression, so FreeMarker prints checked. Otherwise it prints just an empty string.
See https://freemarker.apache.org/docs/ref_builtins_boolean.html#ref_builtin_string_for_boolean

Using <p-dropdown> with form control

I think I am having an issue with value binding. I have 2 dropdowns on my page currently. The rest of the page is using PrimeNg for UI and would like to make these dropdowns look the same as the rest of the page. How should I go about making this work.
One dropdown is a supervisor list.
<div class="ui-g form-group">
<label for="supervisors">Supervisors * </label>
<select
class="form-control"
id="supervisors"
required
[(ngModel)]="model.supervisor"
name="supervisor"
>
<option *ngFor="let sup of supervisors" [value]="sup">
{{sup}}
</option>
<div
[hidden]="supervisors.valid || supervisors.pristine"
class="alert alert-danger"
>
Supervisor is required
</div>
</select>
</div>
The other is a leave code list
<div class="ui-g-12 ui-md-1" id="test">
<label for="codes">Leave Codes * </label>
<select
class="form-control"
id="codes"
placeholder="Select Leave Code *"
required
[(ngModel)]="model.code"
name="code"
>
<option *ngFor="let cod of codes" [value]="cod">{{cod}}</option>
</select>
</div>
I have 2 arrays of values being called from my .ts file
supervisors = ['Alex',"Jones",'Joe','Rogan'];
codes = ['Personal Leave','Vacation Leave', 'Sick Leave'];
When I use the tags I just get an empty drop down. I tried just using initially but then I was not able to get the required fields to validate.
Did you import DropdownModule?
import {DropdownModule} from 'primeng/dropdown';
See the documentation, html binding should be
<p-dropdown [options]="supervisorList" [(ngModel)]="supervisor"></p-dropdown>
where supervisorList will be defined as SelectItem in controller and needs to be in a label + value format.
supervisorList: SelectItem[];
this.supervisorList= [
{label: 'Alex', value: 'Alex'},
...
];

ngModel default value setting doesnt receive info from model

I have a form and I want to set some default values to be shown inside it. I have tried the following code:
<h3>ِStart Time</h3>
<div class="row" >
<div class="col">
<label for="startTime">Hour(s) </label>
<input type="number" [ngModel]="defaultSTime" class="form-control" name="StartTimeHour" value="card.startTime.getHours" id="startTime" min="0" max="23">
</div>
<div class="col">
<label for="startTime">Minute(s) </label>
<input type="number" [ngModel]= "defaultSMinute" class="form-control" name="StartTimeMin" value="card.startTime.getMinutes" id="startTime" min="0"max="59"> <!--input type can be changed accordingly-->
</div>
</div>
defaultSTime = 'card.startTime.getHours' ;
defaultSMinute = 'card.startTime.getMinutes';
this is supposed to work but it only shows me the empty box. where is the problem?
Not sure if this is the issue but from your definition of defaultSTime and defaultSMinute, they are strings while your inputs are defined as number type.
If you're trying to get a number from card object card.startTime.getHours, change your definition to:
defaultSTime = card.startTime.getHours;
defaultSMinute = card.startTime.getMinutes;
This will help you :
[
Also, to make it two way binding, keep banana-in-a-box for ngModel, i.e :
[(ngModel)]= "defaultSMinute"
There, is not much clarity in your comments - how you are constructing Card object, but i believe you missed following:
getHours() ; // these are functions of date not properties

Camunda: Cannot resolve identifier for an exclusive gateway

I tried to use a html form for a user task in which a variable gets defined, to select a sequenzflow in the following exclusive gateway.
html:
<div class="form-group">
<div class="radiobutton">
<label>
<input cam-variable-name="altneu" cam-variable-type="String" type="radio" name="altneu" class="form-control" value="NEU"/>
Neukunde
</label>
<label>
<input cam-variable-name="altneu" cam-variable-type="String" type="radio" name="altneu" class="form-control" value="ALT"/>
Altkunde
</label>
</div>
</div>
Sequenceflows:
<bpmn:sequenceFlow id="SequenceFlow_0a0vwxr" name="Kunden-stammdaten sind vorhanden" sourceRef="ExclusiveGateway_0vokx46" targetRef="ExclusiveGateway_074f3z1">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression"><![CDATA[${altneu == 'ALT'}]]></bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="SequenceFlow_1cwjztj" name="Kundenstammdaten sind nicht vorhanden" sourceRef="ExclusiveGateway_0vokx46" targetRef="Task_1peelfz">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression"><![CDATA[${altneu == 'NEU'}]]></bpmn:conditionExpression>
</bpmn:sequenceFlow>
I get this exception when executing:
An error happend while submitting the task form :
Cannot submit task form 713c798f-ebeb-11e7-9cb1-dcfe074be7ab: Unknown property used in expression: ${altneu == 'NEU'}. Cause: Cannot resolve identifier 'altneu'
I tested your form with camunda bpm 7.8 with the help of the tasklist and got the message, that it is not possible to instantiate a variable with the same name. This means, that the engine is not able to recognize two or more occurrences of the same variable name for the same input variable. Therefore the engine instantiates the variable "altneu" as it finds the input for "NEU". Then it finds "altneu" again and tries again to instantiate "altneu" for "ALT". But "altneu" already exists.
Please refer to the controls section of camunda's manual. It seems, that there is no direct support for radio buttons. If possible you can use a select?
<form role="form" name="form">
<div class="form-group">
<select cam-variable-name="altneu" cam-variable-type="String">
<option value="ALT">Alt</option>
<option value="NEU">Neu</option>
</select>
</div>
</form>
Another alternative could be a checkbox.
<form role="form" name="form">
<div class="form-group">
<label for="neukundeId">Neukunde?</label>
<input type="checkbox" cam-variable-name="isNeu" cam-variable-type="Boolean" id="neukundeId" />
</div>
</form>
Otherwise camunda's hint
If an HTML control is not supported, you need to write custom JavaScript.
is valid.

How to pre-select and update checkboxes in Angular 2+

I want to implement a checklist in Angular. Some boxes have to be pre-checked based on an array in the ts file and the array has to be updated when a checkbox is checked. I am doing it like:
<div class='form-group que-box' *ngFor="let option of currentQuestion.options">
<input type="checkbox" aria-label="Checkbox 1" [value]="option.text" name="checkBox" [(ngModel)]="optionsSelectedArray"/>
<label for='{{option.optionId}}'><span class="que">{{option.text}}</span></label>
</div>
optionsSelectedArray contains the option IDs retrieved from server.
But it doesn't work. All the checkboxes come checked when the the division is rendered.
EDIT
I have changed my code as follows :
<div class='form-group que-box' *ngFor="let option of currentQuestion.options">
<input type="checkbox" id="{{option.optionId}}" name="checkBox" [(ngModel)]="option.userResponse" (ngModelChange)= "setResponseChanged()">
<label for='{{option.optionId}}'><span class="que">{{option.text}}</span></label>
</div>
Here option.userResponse in boolean. Now on selecting the checkboxes the currentQuestion object is correctly changing but when the checklist loads for the first time, the checkboxes are not checked correctly.All the checkboxes come checked if the option.userResponse is true for the last item ,none come checked otherwise.
Perhaps this might do what you want
<div class='form-group que-box' *ngFor="let option of currentQuestion.options; let i=index">
<input type="checkbox" aria-label="Checkbox 1" name="checkBox" [(ngModel)]="optionsSelectedArray[i]"/>
<label for='{{option.optionId}}'><span class="que">{{option.text}}</span></label>
</div>
(I added ; let i=index and [i])