0

<div *ngFor="let conflictRule of conflictRulesMap1 | keyvalue, let p = index">
    <div *ngFor="let ruleContainer of conflictRule.value ,let k = index">
        <div align="left" class="existingRule">
         
               <!-- first CHECKBOX GOES HERE  -->
                <rule [changedConfigDataList]="getChangedConfigDataListConflict(conflictRule.key)"
                [configId]="conflictRule.key" [configLookupMetadata]="configLookupMetadata"
                [disableExpansion]="disableExpansion" [index]="k" [isSaveEnabled]="isSaveEnabled" [mode]="mode"
                [openState]="expandRules" [rule]="ruleContainer.updatedRule">
            </rule>
        </div>
        <div class="ruleSpearator"> OR </div>
        <div align="right" class="updatedRule">

             <!-- second  CHECKBOX GOES HERE  -->

            <rule [changedConfigDataList]="getChangedConfigDataListConflict(conflictRule.key)"
                [configId]="conflictRule.key" [configLookupMetadata]="configLookupMetadata"
                [disableExpansion]="disableExpansion" [index]="k" [isSaveEnabled]="isSaveEnabled" [mode]="mode"
                [openState]="expandRules" [rule]="ruleContainer.originalRule">
            </rule>
        </div>
        .
    </div>
</div>

here i want to add two checkBoxes at the mentioned place. The code is itearating a map for keys , then values for that corresponding key , only one of the two has to be selected..any help about forms or any way to do.

  • It seems your problem is easily solved (without custom controls) if radio buttons are acceptable instead of checkboxes. See the first answer for this question: https://stackoverflow.com/questions/23781707/how-can-i-group-radio-buttons-that-are-in-different-div-tag Also you will want to set on the input same "name" attribute, but different "value" attributes to know what was selected. – mar10 Jun 26 '20 at 21:02
  • If that suggestion suits you, keep in mind that you also need to have the same formControlName attribute (e.g. formControlName="mySelectedOption") on both radio inputs to bind the value to, for example, mySelectedOption variable. You should add a FormControl to your code, see an example in the first answer from this other question about reactive forms: https://stackoverflow.com/questions/49078286/angular-5-reactive-forms-radio-button-group – mar10 Jun 26 '20 at 21:14

2 Answers2

0

Update 2

A version with checkboxes: Stackblitz demo with checkboxes

  • creates a component holding the two checkboxes of a pair
  • passes as @Input() the pair object
  • handled the (change) event on each of the checkboxes
  • create an @Output() event on the component, and when a checkbox was clicked, raise an event to the parent component with the payload ("first" or "second" or null) depending on what selection was made

See more on component interaction via Input-Output here.

A screenshot of the result: The result

Update 1

For your case, radio buttons are recommended. If you can use them, you won't need a custom control.

See stackblitz demo enter image description here

To keep it simple, I am using input radio buttons in a template-based form (it's simpler that using a reactive form).

As you want to select only one of each pair, then:

  1. each pair of radio buttons must be in their own radio buttons group (using input "name" attribute).

Here you must have a unique group name per pair. For example, the current object's key and the index of the pair in the choice list on that key, like that:

[name]="'resolution' + '_' + choice.key + '_' + index"
  1. each pair of radio buttons must be bound to their own variable. The variable says which one of the two buttons was selected. We use [(ngModel)] (two way binding) for binding the variable. For example you could use choiceList (which is the current pair) and just add a property "selected" with the currently selected item of the pair:
[(ngModel)]="choiceList.resolution"

To sum up the two conditions, the two inputs can be:

<input type="radio" [name]="'resolution' + '_' + choice.key + '_' + index" value="first" [(ngModel)]="choiceList.resolution" />

<input type="radio" [name]="'resolution' + '_' + choice.key + '_' + index" value="second" [(ngModel)]="choiceList.resolution" />

Only the "value" attributes differs between the inputs (first|second), as you need to know which one is selected; the selected value will be found in choiceList.resolution variable.


See the full code below:

app.component.html

<div>
  <div *ngFor="let choice of sample | keyvalue">
    <div *ngFor="let choiceList of choice.value; let index = index">
      <p>Key = {{choice.key}}. Index = {{index}}</p>
      <form>
        <div class="firstChoice">
          <div class="existingRule">
            <label>
              <input type="radio" [name]="'resolution' + '_' + choice.key + '_' + index" value="first"
                [(ngModel)]="choiceList.resolution" />
              {{choiceList.first}}
            </label>
          </div>
        </div>
        <div class="ruleSeparator"> OR </div>
        <div class="secondChoice">
          <div class="updatedRule">
            <label>
              <input type="radio" [name]="'resolution' + '_' + choice.key + '_' + index" value="second"
                [(ngModel)]="choiceList.resolution" />
              {{choiceList.second}}
            </label>
          </div>
        </div>
        <p>
          The choice is: <b>{{ choiceList.resolution }}</b>
        </p>
      </form>
    </div>
    <hr>
  </div>
</div>

app.component.ts

import { Component } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';

export interface Choice {
  first: string,
  second: string,
  selected: string
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  form: FormGroup;
  sample;

  constructor(fb: FormBuilder) {
    this.sample = {
      "first": [{
        "first":"first_first",
        "second":"first_second"
        //here we bind a new property "selected" which will contain which selection was made (first|second)
      }],
      "second": [{
        "first": "second_first",
        "second": "second_second"
        //"selected": "first" | "second" (=> based on selection in the form)
      }, {
        "first": "second_third",
        "second": "second_forth"
        //"selected": "first" | "second" (=> based on selection in the form)
      }]
    };
  }
}

You can define the object directly as JSON, as I did above for sample. You used Map<string,Choice[]>, but there is no need to use an explicit Map, all objects are key-value maps in Javascript. To add a new property to the map, you could just say

let key = 'your key'; // I suppose you generate the key programatically
this.sample[key] = [{first: "", second: ""}]; 
mar10
  • 347
  • 1
  • 9
  • again it is not working..saying property name does not exist on type on App Component – Deepak Sharma Jun 28 '20 at 05:36
  • Isnt there a way so that i can get all the value at the time of form submission – Deepak Sharma Jun 28 '20 at 05:46
  • i mean how to add this in form...so that i can get the value of all fields at once on submit click – Deepak Sharma Jun 28 '20 at 05:59
  • and secondly , i have to use checkBox itself..not the radio buttons – Deepak Sharma Jun 28 '20 at 06:41
  • "again it is not working..saying property name does not exist on type on App Component " => I added a link to my stackblitz with my code. As you can see, there is no such error there in my stackblitz, maybe you mixed other code with my code. Also, in Angular you don't need to submit forms to access data. The input radio selection (first|second) is bound to the "resolution" property on each choiceList item from the original object you started with - the "sample" object. I added a stackblitz screenshot with the "sample" object, you can see there the selected choice on each pair. – mar10 Jun 28 '20 at 09:09
  • "Isnt there a way so that i can get all the value at the time of form submission" => all the values are present in the original "sample" object as soon as you click the radio buttons (via [(ngModel)] binding); so, you can add a Submit button and when it is clicked, you can check the "sample" object where - on each pair - you have the "resolution" property filled in with what user selected (first, second or nothing) – mar10 Jun 28 '20 at 09:14
  • "and secondly , i have to use checkBox itself..not the radio buttons" => for that, I would recommend you to create a component holding the two checkboxes of a pair. You should pass as @Input() the pair object. Then, create an @Output() event on the component, and when a checkbox was clicked, raise an event with a string payload "first" or "second" depending on what checkbox was clicked. You should handle the (change) events on the two checkboxes for that. See https://stackoverflow.com/questions/47068222/angular-4-checkbox-change-value/47068667 – mar10 Jun 28 '20 at 09:40
  • 1
    Many thanks to u for your efforts....your solution has reduced my problem to half – Deepak Sharma Jun 28 '20 at 15:04
  • when i add {{choiceList.first}} . instead of – Deepak Sharma Jun 29 '20 at 14:30
  • It is better to give more details instead of a generic "it doesn't work". What behavior you expected and it does not happen? Or do you have an error? You will get a faster answer. Nevertheless, here you need to read the docs: (toggle) is not an @Output for mat-checkbox. toggle() is a method of the component. Round parantheses are only for Output properties (which are event emitters) on the component. You probably wanted (change) instead of (toggle). See MatCheckbox directive - Properties - search for "change" Output property: https://material.angular.io/components/checkbox/api#MatCheckbox – mar10 Jun 29 '20 at 18:46
  • Also, notice that the handler you set on (change) will receive an object of this type: https://material.angular.io/components/checkbox/api#MatCheckboxChange - make sure to adapt your code. – mar10 Jun 29 '20 at 18:50
0

thanks for your reply . But this is not working as expected .

import { Component } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
import {Choice} from './choice'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  form: FormGroup;
  sample : Map<string,Choice[]>;
  constructor(fb: FormBuilder) {
    this.form = fb.group({
      resolution: ['', Validators.required]
    });

    this.sample = new Map();
    let choice1 = {
       first:"first_first",
       second:"first_second",
    }
    let choiceArray: Choice[] = [];
    choiceArray.push(choice1);
    this.sample.set("first",choiceArray);
    choiceArray = [];
    let choice2 = {
       first:"second_first",
       second:"second_second",
    }
    choiceArray.push(choice2);
     let choice3 = {
       first:"second_third",
       second:"second_fourth",
    }
    choiceArray.push(choice3);
    this.sample.set("second",choiceArray);
  
  }
}

<div>
    <div *ngFor="let choice of sample| keyvalue">
    {{choice.key}}------
  <div *ngFor="let choiceList of choice.value">  
        <form [formGroup]="form">
            <div class="firstChoice">
                <div class="existingRule">
                    <label>
        <input type="radio" name="resolution" value="first" formControlName="resolution">
          {{choiceList.first}}
      </label>
                </div>
            </div>
            <div class="ruleSeparator"> OR </div>
            <div class="secondChoice">
                <div class="updatedRule">
                    <label>
        <input type="radio" name="resolution" value="second" formControlName="resolution">
        {{choiceList.second}}
      </label>
                </div>
            </div>
            <p>
                The choice is: <b>{{ form.value.resolution }}</b>
            </p>
        </form>
    </div>
    <hr>
    </div>
</div>
export interface Choice {
  first:string,
  second:string
}

as the list of values is not certain..so there can be list of varying length(differentiated by horizontal line)... but as per your code , when i select any radio box..it get selected for all the fields which i do not want to.

  • So, for example for the "second" key and its options, please tell me, you want to: A. to choose one of (second-first, second-second, second-third, second-forth)? Or B. you always want to choose between pairs of odd and even options, I mean one of (second-first, second-second), then one of (second-third, second-forth) etc? – mar10 Jun 27 '20 at 10:41
  • (not related to the coding question) you can update your original question with details, instead of adding an answer only for details. You simply edit your original question and add at the end of your original question something like Edit 1: and place there additional info :) – mar10 Jun 27 '20 at 10:48
  • yes . option B is correct . For each key, from each pair of values i have to select one option always ..like for key "first" i have to choose one from (first_first , first_second) and for key "second" , i have to choose in pairs that even odd....for ex: one from (second-first, second-second) and another one from (second-third, second-forth) and so on .....which means if a key as N lists, then i have to select n options but from pairs as illustrated in example one of (second-first, second-second), then one of (second-third, second-forth) – Deepak Sharma Jun 27 '20 at 15:36
  • Good! The idea is to have a unique ("name" and "formControlName") for each pair of radio buttons that are in same radio group. So the other groups must have different "name" and "formControlName" attributes. I will update my initial answer to show how this works. – mar10 Jun 27 '20 at 17:35