I have two radio buttons (they're not dynamically generated):
<input type="radio" name="orderbydescending" [(ngModel)]="orderbydescending" [value]="['+recordStartDate']">Ascending<br>
<input type="radio" name="orderbydescending" [(ngModel)]="orderbydescending" [value]="['-recordStartDate']">Descending
How do I make one of the radio buttons checked by default?
Thank you!
Edit
The button's values are being passed through this pipe (i.e. not a component, per se...not sure this is worth mentioning?). The app is pretty simple, and the radio buttons are just hardcoded into app.component. Is the pipe the correct place to initialize which radio button is checked by default?
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({name: 'orderBy', pure: false})
export class OrderByPipe implements PipeTransform {
static _OrderByPipeComparator(a:any, b:any):number{
if((isNaN(parseFloat(a)) || !isFinite(a)) || (isNaN(parseFloat(b)) || !isFinite(b))){
//Isn't a number so lowercase the string to properly compare
if(a.toLowerCase() < b.toLowerCase()) return -1;
if(a.toLowerCase() > b.toLowerCase()) return 1;
}
else{
//Parse strings as numbers to compare properly
if(parseFloat(a) < parseFloat(b)) return -1;
if(parseFloat(a) > parseFloat(b)) return 1;
}
return 0; //equal each other
}
transform(input:any, [config = '+']): any{
if(!Array.isArray(input)) return input;
if(!Array.isArray(config) || (Array.isArray(config) && config.length == 1)){
var propertyToCheck:string = !Array.isArray(config) ? config : config[0];
var desc = propertyToCheck.substr(0, 1) == '-';
//Basic array
if(!propertyToCheck || propertyToCheck == '-' || propertyToCheck == '+'){
return !desc ? input.sort() : input.sort().reverse();
}
else {
var property:string = propertyToCheck.substr(0, 1) == '+' || propertyToCheck.substr(0, 1) == '-'
? propertyToCheck.substr(1)
: propertyToCheck;
return input.sort(function(a:any,b:any){
return !desc
? OrderByPipe._OrderByPipeComparator(a[property], b[property])
: -OrderByPipe._OrderByPipeComparator(a[property], b[property]);
});
}
}
else {
//Loop over property of the array in order and sort
return input.sort(function(a:any,b:any){
for(var i:number = 0; i < config.length; i++){
var desc = config[i].substr(0, 1) == '-';
var property = config[i].substr(0, 1) == '+' || config[i].substr(0, 1) == '-'
? config[i].substr(1)
: config[i];
var comparison = !desc
? OrderByPipe._OrderByPipeComparator(a[property], b[property])
: -OrderByPipe._OrderByPipeComparator(a[property], b[property]);
//Don't return 0 yet in case of needing to sort by next property
if(comparison != 0) return comparison;
}
return 0; //equal each other
});
}
}
Edit 2
So in component.app.ts I've edited my export class AppComponent{ to the following:
export class AppComponent {
artists = ARTISTS;
currentArtist: Artist;
orderbydescending = ['-recordStartDate'];
showArtist(item) {
this.currentArtist = item;
}
}
This works in terms of preventing the previous errors, but it doesn't actually make the radio button selected. It still appears as though it's unselected - even though it functions as though it is. Does this make sense?
If you're doing this in Angular 2+ with 2 way binding, in the component where this HTML is being used, you could just try initializing the value associated with the input.
// in your component ts file
orderbydescending: boolean = true;
and you could leave the HTML the same. Although, you seem to have 2 radio buttons associated with the same data value, orderbydescending. I don't know if that's what you intend, but it looks like it could cause problems.
Here's some code from my personal side project to give you a better idea.
#Component({
selector: 'gmu-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
// here you would put your variables
myFlag: boolean = true;
constructor() { }
ngOnInit() {
}
}
If orderbydescending and recordStartDate are members of your component class:
#Component({
...
})
export class MyComponent {
public recordStartDate: any = ...
public orderbydescending: any = +recordStartDate;
...
}
the appropriate radio button will be checked if you assign the radio button values with [value]:
<input type="radio" name="order" [(ngModel)]="orderbydescending" [value]="+recordStartDate">Ascending<br>
<input type="radio" name="order" [(ngModel)]="orderbydescending" [value]="-recordStartDate">Descending
In the case shown above, the ascending order radio button will be checked by default because the orderbydescending variable is initially set to +recordStartDate.
Note: The variables in my sample code are of type any because I don't know exactly what kind of data you are using. Your data will probably have a more specific data type.
Try this in the component
radioValue = {valueAsc: 'Asc', valueDesc: 'Desc'} ;
orderbydescending = 'Asc';
and in the template put this
<input type="radio" name="radioGroup" [(ngModel)]="orderbydescending" [value]="radioValue.valueAsc">Ascending
<input type="radio" name="radioGroup" [(ngModel)]="orderbydescending" [value]="radioValue.valueDesc">Descending
With this the first radio button is checked, if you don't want any radio button selected assign to the variable orderbydescending null.
orderbydescending = 'null;
Related
I am having some trouble trying to change the css of a button with the (click) event. I managed to do it, but the problem is that I have 10 buttons, so I can't depend on one variable in the .ts because once it changes, it will affect all 10 buttons and not just the one which was clicked, so the only thing I thought was having 10 different variables, but it is not quite elegant. Is there any way of doing it a bit cleaner?
Here is what I've got so far:
html:
<button (click)="b1 = !b1" class="tarea" [id]="cambiaId(b1)"></button>
<button (click)="b2 = !b2" class="tarea" [id]="cambiaId(b2)"></button>
<button (click)="b3 = !b3" class="tarea" [id]="cambiaId(b3)"></button>
[...]
<button (click)="b10 = !b10" class="tarea" [id]="cambiaId(b10)"></button>
ts:
export class TareasComponent {
b1 : boolean = false;
b2 : boolean = false;
b3 : boolean = false;
[...]
b10 : boolean = false;
cambiaId(b : boolean){
if (b) {
return "done";
}else{
return "todo";
}
}
I think you might have some valid reason to have duplicate id for elements. To do it in performant way in angular would be to do with ngFor and trackby. A sample imlementation is available at CodeSandbox Implementation
buttons: ButtonType[] = Array(10)
.fill("todo")
.map((value, i) => ({ id: i, value }));
trackById(index: number, button: ButtonType) {
return button.id;
}
buttonClicked(index: number, button: ButtonType) {
const ret = this.buttons.slice(0);
ret[index] = {
...button,
value: button.value ? "done" : "todo"
};
this.buttons = ret;
}
<ng-container *ngFor="let item of buttons; index as i; trackBy:trackById">
<button [id]="item.value" (click)="buttonClicked(i, item)" class="tarea">
{{item.value}}
</button>
</ng-container>
abc.component.html:
<input class='alignedItem' type="checkbox" value="0" name={{cardProgram.id}}
[indeterminate] ="cardProgram.indeterminate" [checked] = "cardProgram.selected" [(ngModel)]='cardProgram.selected' [disabled]='(cardProgram.appId && !hasOtherAppsAssigned(cardProgram)) && (cardProgram.appId != getAppId())'
(click)='toggleCardProgram(cardProgram,cardProgram.selected)' />
<label class='fa col-1 showMore expand-indicator' [ngClass]="{'fa-plus': !rowIsExpanded(index),
'fa-minus': rowIsExpanded(index)}"
for='{{cardProgram.id}}'></label>
<input #hiddenAnimationInput class='h-0' type="checkbox" id='{{cardProgram.id}}'
(change)='rowClicked(index)' />
<!-- Hidden unless toggled -->
<div class='positionUp25'>
<ul>
<li *ngFor="let agentItem of cardProgram.agents">
<span class='col-12'>
<label class='offset-1TMP col-5'>
{{cardProgram.sys}}/{{cardProgram.prin}}/{{agentItem.agent}}
</label>
<label *ngIf=agentItem.application class='col-6' [ngClass]="{'text-disabled': agentItem.application && agentApp(agentItem) != getAppId()}">
{{agentItem.application.subAppName}}
</label>
<label *ngIf=!agentItem.application class='col-6'>
</label>
<input class='alignedItem ml-3' type="checkbox" name='{{cardProgram.sys}}{{cardProgram.prin}}{{agentItem.agent}}'
#{{cardProgram.sys}}{{cardProgram.prin}}{{agentItem.agent}}='ngModel'
[(ngModel)]='agentItem.selected' (click)='toggleAgent(agentItem, cardProgram)'
[disabled]='agentItem.application && agentApp(agentItem) != getAppId()' />
</span>
</li>
</ul>
</div>
cardPrograms.d.ts:
interface CardProgram {
.......
indeterminate:boolean;
checked:boolean;
......
}
indeterminate.directive.ts
import { Directive, ElementRef,Input } from '#angular/core';
#Directive({ selector: '[indeterminate]' })
export class IndeterminateDirective {
#Input()
set indeterminate(value)
{
this.elem.nativeElement.indeterminate=value;
}
constructor(private elem: ElementRef) {
}
}
abc.component.ts:
private toggleAgent(agent: Agent, cardProgram: CardProgram) {
debugger;
this.dirty = true;
console.log("selected" + agent.selected)
this.updateChangeValToObj(agent, cardProgram)
//agent.selected = !agent.selected;
if (agent.selected) {
agent.application = this.currentApplication();
} else {
agent.application = null;
// if we deselected, also unassign the app at the program level so it will reflect as 'Multiple Apps' state
cardProgram.application = null;
}
// this.togglecheckbox(cardProgram)
var x = 0;
cardProgram.agents.forEach(agent => {
if (agent.selected == true) {
++x;
console.log("inside agent.selected");
}
})
var length = cardProgram.agents.length;
if (x == 0) {
console.log("x is 0");
cardProgram.selected = false;
cardProgram.indeterminate =false;
}
else if (x == length) {
cardProgram.selected = true;
cardProgram.indeterminate =false;
}
else if (x > 0 && x < length) {
cardProgram.selected = false;
cardProgram.indeterminate =true;
}
else{
cardProgram.indeterminate =false;
cardProgram.selected = false;
}
}
When I select all the child check-boxes(agents), the parent should be checked and this works fine.
When all the agents are unchecked, and then I check one of the agents the indeterminate checkbox comes up which is fine.
Problem scenario: The problem comes when I check the parent checkbox which checks all the agents which is fine but when I uncheck one of the agents, that time indeterminate option should show which is not happening. It shows unchecked for parent.
In the abc.component.ts, I see the control goes into else if (x > 0 && x < length) and sets the cardProgram.indeterminate =true; but the indeterminate is not shown in the UI for the above mentioned problem scenario most of the times but strangely works sometimes.
edit: Ok i have come to know exactly how to recreate the issue: lets say there are three child check boxes (agents) and all are unchecked which makes the parent unchecked. Now when I check one of child (shows indeterminate) and then check the parent checkbox(checks all the agents) and uncheck one the child then indeterminate should come up which it does not
I have done something like this before, except it was done using a mat-table and mat-checkbox. But the core implementation remains the same.
I believe the requirement is to display a table or a list with checkboxes to select each row and a master checkbox to check/uncheck all of them, and also to display an indeterminate state when some of the rows are checked.
Something like this could be done using <mat-checkbox> which provides the same functionality as native <input type="checkbox">.
TS file
intialSelection: number[] = [];
allowMultiSelect = true;
selection = new SelectionModel<number>(this.allowMultiSelect, this.intialSelection);
// checks whether the number of selected elements is equal to the total number of elements in the list
isAllSelected() {
const numSelected = this.selection.selected.length;
const numRows = this.sourceData.length;
return numSelected == numRows;
}
// selects all rows if they are not selected; otherwise clears the selection
masterToggle(){
this.isAllSelected() ?
this.selection.clear() :
this.sourceData.forEach(row => this.selection.select(row.Id));
}
HTML File
<!-- The master checkbox -->
<mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
<!-- Checkbox corresponding to individual rows -->
<mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selection.toggle(id) : null"
[checked]="selection.isSelected(id)">
Reference
https://material.angular.io/components/checkbox/overview
<input [indeterminate]="true" class="form-check-input" type="checkbox"/>
I have this data coming from another component
on the basis of active tag when row is clicked I am pushing Id to ngModel of checkbox input field.
Row click is working fine and checkbox is adding/removing data
but now when I click on checkbox itself it doesn't do anything like checkbox click function is not working
How can I solve that?
html component
<ngb-panel [disabled]="true" *ngFor="let testPanel of otherTests; let i = index;" id="{{testPanel.Id}}" [title]="testPanel.Name">
<ng-template ngbPanelTitle>
<div class="action-items">
<label class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
[name]="testPanel.Id + '-' + testPanel.Moniker"
[ngModel]="panelIds.indexOf(testPanel.Id) > -1"
(ngModelChange)="onPanelCheckboxUpdate($event, testPanel)"
[id]="testPanel.Id + '-' + testPanel.Moniker">
<span class="custom-control-indicator"></span>
</label>
</div>
</ng-template>
</ngb-panel>
ts component
getting Id from service and push it on basis of row click
this.testOrderService.refreshRequestsObservable().subscribe(
data => {
this.panelActive = data.active;
let testFilteredArray = lodash.filter(this.otherTests, item => item.Id === data.id);
if (this.panelActive) {
// is checked
this.panelIds.push(data.id);
if(testFilteredArray.length > 0){
this.selectedPanels.push(testFilteredArray[0]);
}
}
else {
//is false
this.panelIds = this.panelIds.filter(obj => obj !== data.id);
this.selectedPanels = this.selectedPanels.filter(obj => obj.Id !== data.id);
}
// this.panelIds = lodash.uniq(this.panelIds);
this.selectedPanels = lodash.uniqBy(this.selectedPanels, "Id");
this.updateSession();
}
)
checkbox function
onPanelCheckboxUpdate($event: boolean, panel: TestOrderPanel) {
let testPanelIds = panel.Tests.map(test => test.Id);
// Wipe any duplicates
this.panelIds = this.panelIds.filter(
panelId => panel.Id !== panelId && testPanelIds.indexOf(panelId) === -1
);
this.selectedPanels = this.selectedPanels.filter(
selectedPanel =>
panel.Id !== selectedPanel.Id &&
testPanelIds.indexOf(selectedPanel.Id) === -1
);
if ($event) {
this.panelIds.push(panel.Id);
this.selectedPanels.push(panel);
}
this.updateSession();
}
This checkbox function is not working and wont let me change the value of checkbox.
And also is there any way of adding click function in ngbPanel tag?
Any help?
Thanks
If you want to achieve two way data binding , use below code.
In foo.html
<input [(ngModel)]="checBxFlag" type="checkbox"/>
In App.module.ts
import { FormsModule } from '#angular/forms';
#NgModule({
imports: [
[...]
FormsModule
],
[...]
})
If you want fire event click of check box ,use (onClick)="somemethod()" in your foo.html file and define method in foo.ts file.
<!--language:lang-html-->
<div class="form-group m-b-40 ">
<input type="text" class="form-control" id="input1">
<span class="bar"></span>
<span class="error_form" id="bname_error_message"></span>
<label for="input1">Regular Input</label>
</div>
In the above html I need to add "form-control-success" class to the input element and keep it true as long as it complies with the state if (pattern.test(bname) && bname !== '')
The same logic should also be applied to the parent element of input. But this time different class "has-success" should be added to the parent class and keep it untill it meets the same condition.
For other cases like else if(bname !== '') and (!pattern.test(bname)) the classes "form-control-success" and "has-success" that has been added to input and its parent respectively should be replaced with their opposite classes "form-control-warning" and "has-warning". This process is bind to "keyup" event. I wonder if there's a method or an elegant way that will reduce the lines of code and keep it simple.
In the clumsy way, the code looks like this:
<!--language: lang-js-->
$("#input1").keyup(function(){
check_bname();
});
function check_bname() {
var pattern = /^[a-zA-Z]*$/;
var bname = $("#input1").val();
if (pattern.test(bname) && bname !== '')
{
$("#bname_error_message").hide();
$("#input1").removeClass("form-control-warning");
$("#input1").parents(".form-group").removeClass("has-warning")
$("#input1").parents(".form-group").addClass("has-success")
$("#input1").addClass("form-control-success");
}
else if(bname === '')
{
$("#bname_error_message").html("Should not be empty");
$("#bname_error_message").show();
$("#input1").removeClass("form-control-success");
$("#input1").parents(".form-group").removeClass("has-success")
$("#input1").addClass("form-control-warning");
$("#input1").parents(".form-group").addClass("has-warning")
}
else
{
$("#bname_error_message").show();
$("#bname_error_message").html("Should contain only Characters");
$("#input1").removeClass("form-control-success");
$("#input1").parents(".form-group").removeClass("has-success")
$("#input1").addClass("form-control-warning");
$("#input1").parents(".form-group").addClass("has-warning")
}
}
here is a version of your code with some more brevity to it and using more dry coding (less repetition), however i havent been able to try the code so it may contain a bug or two, you need to try it before you run, but i hope you get general idea:
<!--language:lang-jquery-->
$elemInput.keyup(function(){
check_bname();
});
function check_bname() {
var pattern = /^[a-zA-Z]*$/,
bname = $elemInput.val(),
$elemInput = $("#input1"),
$elemError = $("#bname_error_message"),
patternMatch = pattern.test(bname) && bname !== '';
$elemError[patternMatch ? 'hide' : 'show']();
$elemError.removeClass(patternMatch ? "form-control-warning" : "form-control-success")
$elemInput.parents(".form-group").removeClass(patternMatch ? "has-warning" : "has-success")
$elemInput.addClass(patternMatch ? "form-control-success" : "form-control-warning");
$elemInput.parents(".form-group").addClass(patternMatch ? "has-success" : "has-warning")
if (!patternMatch) {
$elemError.html(bname === '' ? "Should not be empty" : "Should contain only Characters");
}
}
I think its quite good but I'd suggest some small changes:
Group your else logic in the same block because they are duplicated except the line to set the html text.
Use .parent() instead of .parents(".form-group") to get the input direct parent.
So it could look like this:
$("#input1").keyup(function(){
check_bname();
});
function check_bname() {
var pattern = /^[a-zA-Z]$/;
var bname = $("#input1").val();
if (pattern.test(bname) && bname !== '') {
$("#bname_error_message").hide();
$("#input1").removeClass("form-control-warning");
$("#input1").parent().removeClass("has-warning");
$("#input1").parent().addClass("has-success");
$("#input1").addClass("form-control-success");
} else {
$("#bname_error_message").html(bname === ''? "Should not be empty" : "Should contain only Characters");
$("#input1").removeClass("form-control-success");
$("#input1").parent().removeClass("has-success");
$("#input1").addClass("form-control-warning");
$("#input1").parent().addClass("has-warning");
}
}
$('#input1').on('keyup', function(event) {
check_bname(event.target.value);
});
function check_bname(bname) {
var $bnameInput = $("#input1");
var $bnameErrorMessage = $("#bname_error_message");
var pattern = /^[a-zA-Z]*$/;
if(bname && pattern.test(bname)) {
$("#bname_error_message").hide();
$bnameInput.removeClass("form-control-warning");
$bnameInput.parents(".form-group").removeClass("has-warning");
$bnameInput.addClass("form-control-success");
$bnameInput.parents(".form-group").addClass("has-success");
}
else {
$bnameInput.removeClass("form-control-success");
$bnameInput.parents(".form-group").removeClass("has-success");
$bnameInput.addClass("form-control-warning");
$bnameInput.parents(".form-group").addClass("has-warning");
if (!bname) {
$bnameErrorMessage.text("Should not be empty");
}
else {
$bnameErrorMessage.text("Should contain only Characters");
}
$bnameErrorMessage.show();
}
}
Is there anyway to detect removed character from a text using ngModel in Angular 2 ?
I want something like:
Original text: #Hello World !
Modified text : Hello World !
Console.log
Removed character: '#'
I've found a cool example on Javascript with Jquery by Arie Xiao below:
https://stackoverflow.com/a/17005983/5668956
But I wonder if I can use another thing beside Jquery, as I find that Jquery is pretty hard to implement in Angular 2
I would suggest a Forms controller for acting on changes on the input field. The snippet displays the character add or deleted from the input field.
Check out my Plunker to see the code running.
#Component({
selector: 'app-root',
template: `
<input type="text" [formControl]="form" class="form-control" >
<h3 *ngIf="initial">
Text <span [style.color]="textadd ? 'green' : 'red'" > {{textadd ? "add" : "removed" }} </span>: {{change}}
</h3>
`,
})
export class App {
form;
textadd;
text = "#Hello World!";
initial = false;
change;
ngOnInit() {
this.form = new FormControl({ value: this.text, disabled: false });
this.form.valueChanges.subscribe(val => {
let change;
if (val.length > this.text.length) {
change = val;
for (let variable of this.text) {
change = change.replace(variable, '');
this.textadd = true;
}
} else {
change = this.text;
for (let variable of val) {
change = change.replace(variable, '');
this.textadd = false;
}
}
this.change = change;
this.text = val;
this.initial = true;
});
}
}