value not binding on choose from list with angular ngDefaultControl - javascript

I have list of option and using ngDefaultControl Angular directive but formcontrol value show empty on button click.
I want to bind value to form control on button click without using setValue or patchValue methods.
example:
<h3>input text search dropdown</h3>
<div class="result">
Selected Value:
{{
rootForm.get('category')?.value
? rootForm.get('category')?.value
: 'Please select value'
}}
</div>
<br />
<form [formGroup]="rootForm">
<div class="list-popup">
<ul class="list" [formControlName]="'category'" ngDefaultControl>
<li class="item" *ngFor="let option of listValues" [value]="option">
<button type="button" class="item-option" tabindex="-1">
<span class="item-label">{{ option }}</span>
</button>
</li>
</ul>
</div>
</form>
is it possible to bind value from UI in control for the same on selection? Could you please suggest me workaround.
here is the stackblitz
Thanks in advance.

Angular doesn't know what to do when you put a formControl on a ul. In order to do what you want, you have to create a component (or directive) which implements ControlValueAccessor and move the code related to your form control there.
Implementing ControlValueAccessor means implementing the following three functions: writeValue, registerOnChange, registerOnTouched. In this way, Angular will know what to do with your component.
For example, you can follow this example

Related

How do I write html for form with multiple questions that use radio input type?

I have this quiz in multiple choice format where users can select one option per question and submit their answers at the end. This example shows what I'm trying achieve: [Example code w3school][1]
The problem I'm having is that selecting an option on a question de-selects any previous selection, meaning only one option can be selected for the entire quiz.
This is a section of my form template:
<form #submit.prevent="submit">
<div v-for="question in questions" :key="question.id">
<jet-label :for="question.question" :value="question.question" class="font-bold text-lg" />
<div v-for="option in question.options" :key="option.id">
<jet-label :for="option.option" :value="option.option" />
<input :id="option.id" type="radio" :value="option.option"
:name="option.question_id" v-model="form.options" />
</div>
</div>
<div class="flex items-center justify-end mt-4">
<jet-button class="ml-4" :class="{ 'opacity-25': form.processing }"
:disabled="form.processing">
Submit
</jet-button>
</div>
</form>
And this is the JS to handle user selection binding:
<script setup>
...
import { useForm } from '#inertiajs/inertia-vue3'
defineProps({
questions: Array
})
const form = useForm({
options: []
})
...
</script>
The issue probably is that inputs are seen as belonging to one group. How can I group the inputs based on the question id so that the select/deselect radio action is per question?
[1]: https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_radio
v-model="form.options" seems to be the problem, all inputs have the same model.
Everytime a radio is selected it overwrites the this.options with the option value.
Try:
v-model="form.options[option.question_id]"
if that dosen't work try to add a custom event handler with #change
BTW: option.question_id is a weird data structure it meight be better to have the id in the question object, because it seems the options lay in an array inside the question object

Toggle button inside angular reactive form

In my angular reactive form i am trying to use three state toggle switch for which i have tried three state switch separately in the link
Three state toggle stackblitz: https://stackblitz.com/edit/angular-6-template-driven-form-validation-gh1dj1
And i need to implement the same with same css inside reactive form on each row inside formarray.
For which i have tried the same html and css and given as formcontrolname like,
<div class="switch-toggle switch-3 switch-candy">
<ng-container #buttonIcon *ngFor="let option of options" >
<input type="radio" formControlName="state" [checked]="value === option"
[value]="option" />
<label (click)="onSelectionChange(option)" for="{{option}}">{{option.id}}
</label></ng-container> <a></a>
</div>
But i couldn't achieve the result.
Reactive form stackblitz: https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-yqraay
Please click over the add button in the second stackblitz to see the result.. Added the css in app.component.css..
Kindly help me to implement the three state toggle switch as like in the first stackblitz into the reactive form in second stackblitz and need to get the values of selected toggle..
Just add an [id] to the input tag and an [attr.for] to the label tag. Something like this:
<div
class="switch-toggle switch-3 switch-candy">
<ng-container
#buttonIcon
*ngFor="let option of options">
<input
type="radio"
formControlName="state"
[value]="option"
[id]="i+option" />
<label
[attr.for]="i+option">
{{option}}
</label>
</ng-container>
<a></a>
</div>
Here's a Working Sample StackBlitz for your ref.
Thanks to A.Winnen for his comments on the performance implications of using the previous approach.
The options array in your reactive component is different than the 3 way switch you implemented. The one in the real component does not have the id.
[
"on",
"na",
"off"
]
You can still use that like this:
<ng-container #buttonIcon *ngFor="let option of options" >
<input type="radio" formControlName="state" [checked]="value === option"
[value]="option" />
<label (click)="onSelectionChange(option)" for="{{option}}">
{{option}} //**refer the object as the id filed is missing**
</label>
Second difference is, you are missing the onSelectionChange function in your reactive component
Here's a stackblitz demo for your referance.
https://stackblitz.com/edit/angular-szsw3k

Angular 5 click event on cloned DOM structure not triggering

So I have a hidden DOM structure that I will make visible when clicking on a button (to add some input fields). Now I also want to remove those input fields if not necessary anymore. This is my structure that I clone with jQuery:
<ul id="CTcontainer" class='hidden removeContainer'>
<li>
<label>Content Type Name:</label>
<input class="json-input" type="text" name="CT_name">
</li>
<li>
<label>Content Type Group:</label>
<input class="json-input" type="text" name="CT_group">
</li>
<li *ngIf="contentTypeArray.length != '0'">
<label>Inherit from Content Type:</label>
<select class="json-input" name="CT_contentTypeInherit">
<option *ngFor="let ct of contentTypeArray">{{ ct.name }}</option>
</select>
</li>
<li>
<button type="button" class="btnSubmit" (click)="removeThisCT($event)">Remove these ContentType input fields</button>
</li>
</ul>
Clicking on the "add" button:
public addNewCT(event: Event) {
$('#ContentTypes').append($('#CTcontainer').clone(true, true).removeAttr('id').removeClass('hidden'));
}
When then clicking on the button it should fire this:
public removeThisCT(event: Event) {
alert('testclick');
console.log('testclick');
// $(this).closest('.removeContainer').remove();
}
But nothing happens, debugging in dev tools also shows I'm not entering the function when clicking the button. It seems like my event isn't cloned with? Looking at jQuery .clone() it said to add (true, true) to clone with dataAndEvents and deep events etc. but seemingly doesn't work?
Is this because it's an angular on click event and not a jquery .on('click',) event?
Angular will compile your whole template into javascript to make it fast loading, easy to compress, able to deliver your app as a single file and so forth. More importantly in your case, adding angular template code on the fly will not work, since you are completely bypassing the angular compiler.
As a rule of thumb; when you're writing jquery to manipulate the DOM, you should really question yourself if this really is what you want, and if there's no Angular way of dong it. For a start, all component included in an ngIf or ngFor will be removed completely from the dom once the ngIf turns false or the ngFor does not contain the same numer of elements no more. Use them, and ditch the jquery.
If you want to include whole sets of logic dynamically, read this specific part of the guide:
https://angular.io/guide/dynamic-component-loader
A little piece of code that might help you:
<ul *ngIf="cts.length > 0">
<ng-template ngFor let-ct [ngForOf]="cts">
<li>
<label>Content Type Name:</label>
<input class="json-input" type="text" name="CT_name">
</li>
<li>
<label>Content Type Group:</label>
<input class="json-input" type="text" name="CT_group">
</li>
<li *ngIf="contentTypeArray.length != '0'">
<label>Inherit from Content Type:</label>
<select class="json-input" name="CT_contentTypeInherit">
<option *ngFor="let ct of contentTypeArray">{{ ct.name }}</option>
</select>
</li>
<li>
<button type="button" class="btnSubmit"
(click)="removeThisCT($event)">Remove these ContentType input fields</button>
</li>
</ng-template>
</ul>
adding a ct (whatever that may mean, don't use abreviations in code)
public addNewCT(event: Event) {
this.cts.push({name: 'new ct'});
}
public removeCT(event: Event) {
this.cts = [...this.cts.filter(ct => ct.name != event.name)];
}

Typescript : update value from input

I have a list of restaurants made by *ngFor. I can click on the one I wanna change which make it an input field with the label text in it.
What I want to do do is to get the text value of the input field and update the label value with it when I click a button.
You'll understand better with the code :
<div class="row" *ngFor="let restaurant of event.restaurants; let index = index">
<div class="col-xs-5" (click)="update=true" off-click="update=false">
<input *ngIf="update" type="text" name="champ" value="{{restaurant.name}}" placeholder="{{restaurant.name}}"/>
<a *ngIf="!update">{{restaurant.name}}</a>
</div>
<div class="col-xs-5">
{{restaurant.category.description}}
</div>
<div class="col-xs-2">
<button class="btn btn-default" *ngIf="!update" (click)="DelRestaurant(index)">{{'EVENT_RESTAURANT_REMOVE' | translate}}</button>
<button class="btn btn-default" *ngIf="update" (click)="UpdateRestaurant(index)">Modifier</button>
</div>
</div>
With UpdateRestaurant(index), I want to get the input value and change {{restaurant.name}}
If you could help me that would be awesome :)
With UpdateRestaurant(index), I want to get the input value and change
{{restaurant.name}}
I'm not 100% sure with Angular2, however with Angular for repeated entries you could pass in the object associated with the section.
Which means you can pass the restaurant object..
(click)="UpdateRestaurant(restaurant)"
With the object loaded changing the "name" on the object will change the view.

How can I generate multiple pairs of a number field and a checkbox? (checkbox disables one number field)

I'm trying to generate multiple pairs of a number form and a checkbox.
Clicking the checkbox disables the number field, The problem is that only the first pair is working. Can someone help me?
here's my code: addHRGrade.blade.php
#extends('layouts.default')
#section('content')
<!-- opening the form -->
{{ Form::open(array('url' => 'students/create', 'method' => 'PUT')) }}
#foreach($students as $stud)
<ul>
<li>
<!-- Printing the students retrieved from the dataabase -->
{{ $stud->LName. " , " .$stud->FName }}
<!-- Making a text field for every students -->
<div ng-app="" >
<input name="grade" id="no_grade" type="checkbox" value="0" ng-model="checked" />
<label>No Grade</label>
<input name="grade" id="num_grade" type="number" value="65" ng-model="number" ng-disabled="checked"/>
</div>
</li>
</ul>
#endforeach
<!-- Save button -->
<p> {{Form::submit('Save')}} </p>
<!-- Closing the form -->
{{ Form::close() }}
#stop
Main issue
You're declaring one ng-app="" per table row. I don't think that's what you want to do. You should wrap everything into a single app. Also, you don't assign anything to ngApp and also ngController so your not able to implement any further logic.
Side issues
When you fixed the main issue, you'll see, that every checkbox and textbox will display the same value, since you assign the same model to each checkbox resp. textbox.
The value="65" won't do anything. You want to display the models data, so the models data (which is undefined at startup). To set the initial value use ng-init="number=65".

Categories