Button behaving globally and not for each item in Salesforce LWC - apex

I am quite new to Lighting Web Component. However, I have some experience with other component base frameworks.
I'm creating a button for each item and when the button is clicked for each item. It applies to all items. In other words, when one clicks 'Extend' it is meant to show a date input for that specific item but it shows too all of them. This is how my code looks like:
<template>
<template if:true={subscriptionData}>
<template for:each={subscriptionData} for:item="subscriptionItem">
<div key={subscriptionItem.Id}>
<div>
<div class="slds-grid slds-gutters slds-grid_vertical-align-center">
<div class="slds-col custom-card-title-container">
<h2 class="custom-title">{subscriptionItem.SBQQ__ProductName__c}</h2>
</div>
<div class="slds-col button-custom">
<lightning-button label="Extend" title="Non-primary action" onclick={handleShowEditEndDate} class="slds-m-right_none custom-margin"></lightning-button>
</div>
</div>
<div class="slds-grid slds-m-top_xx-small">
<div class="slds-col">
<div class="slds-grid slds-grid_vertical">
<div class="slds-col slds-m-bottom_xx-small">
<span>Start Date</span>
</div>
<div class="slds-col">
<span>{subscriptionItem.SBQQ__StartDate__c}</span>
</div>
</div>
</div>
<div class="slds-col">
<div class="slds-grid slds-grid_vertical">
<div class="slds-col slds-m-bottom_xx-small">
<span>End Date</span>
</div>
<div class="slds-col">
<span>{subscriptionItem.SBQQ__EndDate__c}</span>
</div>
</div>
</div>
<div class="slds-col">
<div class="slds-grid slds-grid_vertical">
<div class="slds-col slds-m-bottom_xx-small">
<span>Quantity</span>
</div>
<div class="slds-col">
<span>{subscriptionItem.SBQQ__Quantity__c}</span>
</div>
</div>
</div>
</div>
<template if:true={showEditField}>
<lightning-layout multiple-rows class="slds-m-top_xx-small">
<lightning-layout-item size="8">
<lightning-input
type="date"
name="endDateInput"
label="End Date"
variant="label-inline"
>
</lightning-input>
</lightning-layout-item>
</lightning-layout>
</template>
<hr class = "custom-line">
</div>
</div>
</template>
</template>
export default class ExtendCPQSubscriptionLWC extends LightningElement {
#api recordId;
#track subscriptionData;
#track columns = columns;
showEditField = false
#wire(getSubscriptionsLWC, { recordId: '$recordId'})
loadFoundSubscriptions({error, data}) {
if (data) {
console.log('OK');
console.log(data);
this.subscriptionData = data;
} else if (error) {
console.log('ERR ' + JSON.stringify(error));
}
}
I would appreciate any input thanks in advance.

You have common showEditField used to control visibility/addition of date input. My recommendation is to move that information inside subscriptionData and update the track variable. This would trigger re-render of UI and only show that field for item, for which Extend button was clicked

Related

Div is not opening below particular ngFor in Angular 6

I am iterating ngFor in angular 6. When i am clicking on button a div should open beside row of that particular button but it is opening below ngFor like this
I want to make it open for that partcular row and below that.
<app-filter></app-filter>
<div class="bg-white" *ngFor="let data of dashboardData">
<div class="container-fluid">
<div class="center-align row">
<div class="col-sm-12">
<div class="block col-sm-2">
{{data.firstname}}{{data.lastname}}
</div>
<div class="block_l col-sm-3">
<span class="light_small">68%</span>
{{data.stage}}
</div>
<div class="block_l col-sm-1">
Customer
</div>
<div class="block_l col-sm-1">
<img src="assets/images/call.png">
</div>
<div class="block_l col-sm-1">
<img src="assets/images/mail.png">
</div>
<div class="block_l col-sm-2">
<span class="status_color"><b>.</b></span>
Paused
</div>
<div class="block_l col-sm-2">
<a class="btn button_css" (click)="openLayout=!openLayout">verify Details</a>
</div>
</div>
</div>
</div>
<div class="bg-loader"></div>
<div class="container" [hidden]="openLayout">
<div class="row">
<app-form-layout></app-form-layout>
<app-form-desc></app-form-desc>
</div>
</div>
</div>
Now it is coming like this
Desired behavior will be like this It's like accordian on click it should open below that row and rest of below rows will be shifted downwards
The problem resides into openLayout variable that is shared for all your rows.
You need one openLayout for each row. you can add it dinamically to your data like this:
<div class="bg-white" *ngFor="let data of dashboardData">
<div class="container-fluid">
<div class="center-align row">
<div class="col-sm-12">
<div class="block col-sm-2">
{{data.firstname}}{{data.lastname}}
</div>
<div class="block_l col-sm-3">
<span class="light_small">68%</span>
{{data.stage}}
</div>
<div class="block_l col-sm-1">
Customer
</div>
<div class="block_l col-sm-1">
<img src="assets/images/call.png">
</div>
<div class="block_l col-sm-1">
<img src="assets/images/mail.png">
</div>
<div class="block_l col-sm-2">
<span class="status_color"><b>.</b></span>
Paused
</div>
<div class="block_l col-sm-2">
<a class="btn button_css" (click)="data.openLayout=!data.openLayout">verify Details</a>
</div>
</div>
</div>
</div>
<div class="bg-loader"></div>
<div class="container" [hidden]="data.openLayout">
<div class="row">
<app-form-layout></app-form-layout>
<app-form-desc></app-form-desc>
</div>
</div>
</div>
At the beginning it will be false because undefined is like false.

Angular 5: Obtaining form input value whether changed or not

How can I pass to onNext() the form's input value of the control named "Category1"? When the form is changed the value is passed but when the user doesn't change the value isn't. I need the value always passed. How do I do this?
<div class="app-form container-fluid">
<div class="row">
<div class="col-6">
<div class="button-left float-left">
<button (click)="onPrevious('tab-empinfo')">Previous</button>
</div>
</div>
<div class="col-6">
<div class="button-right float-right">
<button
(click)="onNext('tab-selection', {
form: 'category',
data: {category: formCategory.value['Category1']}})">
Next
</button>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<h4>Category</h4>
</div>
</div>
<div class="row">
<div class="col-12">
<form #formCategory="ngForm">
<div class="form-group" *ngFor="let input of categorySelection; let i = index">
<choice *ngIf="input.type == 'choice'" name="Category{{ i + 1 }}" ngModel
[multiple]="input.multiple" [question]="input.question" [answers]="input.answers"></choice>
</div>
</form>
</div>
</div>
</div>
<pre>
{{ formCategory.value | json }}
</pre>
Please see screen shot:
Try using an input tag instead of choice. Set the [(ngmodel)] to a property of your container, e.g. category1 and use the same name for each input. It does not need to match the property name, I arbitrarily set it to be category1. Set category1 property to the default value. The component's category1 property value will initialize one of the radio button to be set. Use the category1 property in your on click method parameter.
See https://stackblitz.com/edit/angular-yq5w2y?file=app/app.component.ts for a working example.
<div class="app-form container-fluid">
<div class="row">
<div class="col-6">
<div class="button-left float-left">
<button (click)="onPrevious('tab-empinfo')">Previous</button>
</div>
</div>
<div class="col-6">
<div class="button-right float-right">
<button
(click)="onNext('tab-selection', {
form: 'category',
data: {category: category1}})">
Next
</button>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<h4>Category</h4>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group" *ngFor="let input of categorySelection">
<input type="radio" *ngIf="input.type == 'radio'" [(ngModel)]="category1" name="category1" value="{{input.answer}}" > {{input.answer}}
</div>
</div>
</div>
</div>
----
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular 5';
categorySelection = [{type: 'radio', answer: "who"}, {type: 'radio', answer: "what"}];
category1 = "who";
result;
onPrevious(data: string) {
this.result = data;
}
onNext(x, data: any): any {
this.result = data;
}
}

Ionic Text color change onclick

I'm a beginner in Ionic 3.
I have a 4 text in same color, I'm trying to make when I click on the 4 text at for time I want to change color.
Example
I click on 1st text, then I want to change it black color
I click on text 2, then I want to change black color and 1st text is set a default color,
Please help me to fix this issue
<div class="row">
<div class="col right-border">
<div text-center>
<h2 class="main-one" >$ 2,300</h2> <p class="main-txt-home">Today's Revenue</p>
</div>
</div>
<div class="col bottom-border">
<div text-center>
<h2 class="main-one">$ 53,100</h2><p class="main-txt-home">Expected Revenue for this month</p>
</div>
</div>
</div>
<div class="row">
<div class="col top-border">
<div text-center>
<h2 class="main-one">12</h2><p class="main-txt-home"> Bookings taken today</p>
</div>
</div>
<div class="col left-border">
<div text-center>
<h2 class="main-one">68%</h2><p class="main-txt-home">Total Monthly occupancy</p>
</div>
</div>
</div>
</div>
You can use [ngClass] attribute to achieve this. This can be used to dynamically return the class name as per the last clicked text. The code will be something like below.
<div class="row">
<div class="col right-border">
<div text-center [ngClass]="getTextColor('text1')" (click)="setSelectedText('text1')">
<h2 class="main-one" >$ 2,300</h2> <p class="main-txt-home">Today's Revenue</p>
</div>
</div>
<div class="col bottom-border">
<div text-center [ngClass]="getTextColor('text2')" (click)="setSelectedText('text2')">
<h2 class="main-one">$ 53,100</h2><p class="main-txt-home">Expected Revenue for this month</p>
</div>
</div>
</div>
<div class="row">
<div class="col top-border">
<div text-center [ngClass]="getTextColor('text3')" (click)="setSelectedText('text3')">
<h2 class="main-one">12</h2><p class="main-txt-home"> Bookings taken today</p>
</div>
</div>
<div class="col left-border">
<div text-center>
<h2 class="main-one">68%</h2><p class="main-txt-home">Total Monthly occupancy</p>
</div>
</div>
</div>
In controller
private selecteTextId :string;
setSelectedText(textId:string) {
this.selecteTextId = textId;
}
getTextColor(textId:string):string{
return this.selecteTextId == textId? "highlight-color" : "";
}
In scss file
.highlight-color {
color:blue;
}

Accordion open next on button click

Hi been searching for few days now but couldnt find anything. I have an accordion that has three accordion group, I have added a button to open the next accordion but cant seem to get it working. Can some one please help. here is what I have so far
<accordion [closeOthers]="true" style="margin-top:5px;">
<accordion-group *ngFor="let registration of registrationArray; let i = index" #groupval style="margin-top:5px;" [isOpen]="registration.isAccordionOpen">
<div accordion-heading style="width:100%;">
Registrant No. {{i + 1}}
<i class="pull-right float-xs-right glyphicon"
[ngClass]="{'glyphicon-chevron-down': groupval?.isOpen, 'glyphicon-chevron-up': !groupval?.isOpen}"></i>
</div>
<form [formGroup]="myGroup" (ngSubmit)="gotoAddons(myDetails)">
<div formArrayName="myDetails">
<div class="panel-body" [formGroupName]="i">
<div style="padding-top:20px;clear:both;">
<div style="width:100%;background-color:#578ebe;border: 1px solid #7ca7cc;">
Your Address
</div>
<div style="padding-top:30px;clear:both;">
<div style="width:100%">
<div style="float:left;width:30%;text-align:right;">
<span class="required">*</span><label>Address Line 1</label>
</div>
<div style="float:left;width:70%;padding-left:10px;">
<input autofocus class="form-control" type="text" id="address" name="address" formControlName="address" required>
<div *ngIf="myGroup.controls.myDetails.controls[i].controls.address.errors && (myGroup.controls.myDetails.controls[i].controls.address.dirty || myGroup.controls.myDetails.controls[i].controls.address.touched || submitted)" class="alert alert-danger">
<div [hidden]="!myGroup.controls.myDetails.controls[i].controls.address.errors.required">
Address Line 1 is required!
</div>
</div>
</div>
</div>
</div>
</div>
<div style="width:100%;" *ngIf="i < registrationArray.length - 1">
<div style="float:right;">
<button (click)="groupval.isOpen = !groupval.isOpen" class="btn green">Open next tab</button>
</div>
</div>
<div style="width:100%;" *ngIf="i == registrationArray.length - 1" >
<div style="float:right;">
<button type="submit" class="btn green">Continue</button>
</div>
</div>
</div>
</div>
</form>
</accordion-group>
</accordion>
Removed some code for clarification. Can some one please let me know how I can open the next accordion group on the button click. Thanks in advance
Here is a working example
plunkr
stackblitz link
stackblitz
In your case I see that you're actually just closing the opened panel and that's all. Along with this you need to open a next panel which can be done by setting its isOpen property to true.
A small plunkr with test implementation - https://stackblitz.com/edit/ngx-bootstrap-ifmpph?file=app/app.component.html

CQ5 : Could not edit CQ5 Text Component in Hidden container

We are developing a Tab Component in CQ5/AEM. The component contains 3 Tabs and each tab has one CQ5 text component to edit content.
But only the first tab's Text Component is editable as it is shown by default. The other text components which are in hidden tabs content area are not accessible to edit.
Sample code:
<div>
<div>
<div id="tabcnt1">
<div id="tab1" class="tablink">Tab 1</div>
</div>
<div id="tabcnt2">
<div id="tab2" class="tablink">Tab 2</div>
</div>
<div id="tabcnt3">
<div id="tab3" class="tablink">Tab 3</div>
</div>
</div>
<div class="plantabcontent">
<div id="plancontenttab1" class="plancontent">
<cq:include path="plandescription1" resourceType="libs/foundation/components/text" />
</div>
<div id="plancontenttab2" class="plancontent" style="display:none;">
<cq:include path="plandescription2" resourceType="libs/foundation/components/text" />
</div>
<div id="plancontenttab3" class="plancontent" style="display:none;">
<cq:include path="plandescription3" resourceType="libs/foundation/components/text" />
</div>
</div>
Script:
$(document).ready(function(){
$('.tablink').click(function(){
$(".tablink").removeClass('selecttab').addClass('plantxt');
var tabid = $(this).attr("id");
$("#"+tabid).addClass('selecttab').removeClass('plantxt');
$(".plancontent").hide();
$("#plancontent"+tabid).show();
});
});
The 'plandescription1' is visible by default and it is working fine. But the hidden text components are not working while enabling them by changing tabs.
Kindly show me some light. Thanks in advance.
It's important to load the tab components (text component) when loading the page. In case the components are disabled by default the components are not initialized by AEM. So disable the 'hidden' tabs on document.ready instead of using the style="display:none".
In the example I have added the $("div.plancontent:not(:first)").hide(); to disable all tabs except the first.
Example:
<div>
<div>
<div id="tab1" class="tablink">Tab 1</div>
<div id="plancontenttab1" class="plancontent">
<cq:include path="plandescription1" resourceType="/libs/foundation/components/text" />
</div>
</div>
<div>
<div id="tab2" class="tablink">Tab 2</div>
<div id="plancontenttab2" class="plancontent">
<cq:include path="plandescription2" resourceType="/libs/foundation/components/text" />
</div>
</div>
<div >
<div id="tab3" class="tablink">Tab 3</div>
<div id="plancontenttab3" class="plancontent">
<cq:include path="plandescription3" resourceType="/libs/foundation/components/text" />
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
//Disable all tabs except first
$("div.plancontent:not(:first)").hide();
//Set clickevent
$('.tablink').click(function(){
$(".tablink").removeClass('selecttab').addClass('plantxt');
var tabid = $(this).attr("id");
$("#"+tabid).addClass('selecttab').removeClass('plantxt');
$(".plancontent").hide();
$("#plancontent"+tabid).show();
});
});
</script>