Change elements of one specific div of *ngFor - html

I have this layout. What I want to do is, when a button Join is clicked, hide that button and show an input field in its place like this, and if another button is clicked the first one returns to its normal state and another input field is displayed like this.
I'm working with Angular 13. Here is a code snippet of the concerned div.
<div *ngIf='show === "default"' class="list">
<div class="form-listItem" *ngFor="let room of roomList">
{{ room }}
<button class="formBtn" (click)="enterPassword($event.target)" id="{{ room }}">Join</button>
<div class="joinRoomPasswordContainer" id="{{ room }}-">
<input class="joinRoomPassword" type="password" placeholder="********">
<button class="joinRoomBtn">
<img class="rightArrow" src="/assets/rightArrow.svg" alt="">
</button>
</div>
</div>
</div>

In the Ts file you initialize two variable with boolean type true and false.
and create write a fun like:-
func1(){
this.a = true;
this.b = false;
}
call this function on the button and the panel you want to open on click that div give - *ngIf with these two variable.

you could add a property for room object, some like 'joined', then add ngIf directive for view change
<button class="formBtn" *ngIf="!room.joined" (click)="enterPassword($event.target); room.joined = true" id="{{ room
}}">Join</button>
<div class="joinRoomPasswordContainer" id="{{ room }}-" *ngIf="room.joined">
<input class="joinRoomPassword" type="password" placeholder="********">
<button class="joinRoomBtn">
<img class="rightArrow" src="/assets/rightArrow.svg" alt="">
</button>
</div>

Related

how to style a selected mat-button in an angular application

I have an Angular application where the user has multiple choices with buttons and when a button is pressed another component will display. The component depends on the user's choice.
One thing I'm trying to implement is the styling of the buttons to make it clear which choice has been selected.
<div fxLayout="row" fxLayoutAlign="space-between center" fxFill>
<div *ngFor="let button of buttons">
<button
mat-stroked-button
*ngIf="button.type === 'button'"
(click)="buttonPressed()"
ngxScrollTo
>
{{ button.text }}
</button>
</div>
<div fxLayout="row" fxLayoutAlign="space-between center">
<div *ngIf="item.hasSomeProperty | isTypeButton">
<button mat-mini-fab (click)="buttonPressed()">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
I have also attached a picture of what im trying to achieve here:
Any help would be much appreciated.
Simply use [ngClass] or [ngStyle]:
<div *ngFor="let button of buttons">
<button
mat-stroked-button
*ngIf="button.type === 'button'"
[ngClass]="{'disabledButton': !button.selected}"
(click)="buttonPressed(button)"
ngxScrollTo
>
{{ button.text }}
</button>
</div>
Assuming that your button model contains the "selected" property (or you have some other model storing information which button was actually clicked):
buttonPressed(button: Button) {
// Mark only button as selected
this.buttons.forEach(b => b.selected = b === button);
}
And of course add some class in the css:
.disabledButton {
opacity: 0.75;
}
Note - writing this from top of my head (since no stackblitz was provided) so some adjustments might be needed.

how to show the div when clicked on the link and how to get value from input?

i have a django template that uses for loop to print comments i want to show the input field and a button when the edit link is clicked how do i do that.
and also when the edit button is pressed i wanna get the value from that specific input field. how do i do that?
{% for comment in comments %}
<div class="comment mdl-color-text--grey-700">
<header class="comment__header">
<img src="images/co1.jpg" class="comment__avatar">
<div class="comment__author">
<strong>{{comment.User_name}}</strong>
<span>{{comment.date}}</span>
</div>
</header>
<div class="comment__text">
{{comment.text}}
</div>
<!-- FAB button , class "mdl-button--fab"-->
<a href="javascript:delete_comment('{{comment.text}}','{{comment.blogslug}}')">
<button class="mdl-button mdl-js-button mdl-button--fab">
<i class="material-icons">delete</i>
</button>
</a>
<!--when this link is clicked bellow edit_comment div should appear -->
<a href="">
<button class="mdl-button mdl-js-button mdl-button--fab">
<i class="material-icons">edit</i>
</button>
</a>
<!-- and also when i click the edit button how can i get value from the input -->
<div id="edit_comment" style="visibility: hidden;">
<input type="text" name="edit_comment">
<button>edit</button>
</div>
</div>
{% endfor %}
so the problem is there are going to many other comments of this type because they are printed using a loop.
Firstly, why are you wrapping your button in an <a> tag? Unnecessary.
Get rid of visibility: hidden. Use display: none or a class like Bootstrap's d-none.
I suggest d-none because it allows you to add the class and remove it without worrying about the inherited display property, i.e. display: flex or display: block.
https://getbootstrap.com/docs/4.0/utilities/display/
Write a custom function with an event listener.
Inside your template loop:
<button class="mdl-button mdl-js-button mdl-button--fab" onclick="handleClick(this)">
<i class="material-icons">edit</i>
</button>
ASSUMING YOU HAVE REMOVED THE <a> TAG
JavaScript:
let handleClick = function(param) {
let editCommentDiv = param.parentNode.lastChild;
editCommentDiv.style.display = "none"
};
This is by no means the best way to do it. I highly suggest you use BootStrap's d-none class. Also, what you should actually do is assign an ID based on the for loop to both the button and to the div, i.e. id=editcommentdiv_{{ forloop.counter }} this way you won't need to use DOM to navigate to the last element to get the edit div, and can just target the div directly via ID.

How do I get a button used on multiple card containers to only affect one container at a time?

I am currently working on a web application using angular and angular material. The page in question holds several profiles each with a button that when clicked removes the information currently showing and replaces it with the rest of the profile information. The issue is that when I click this button on one profile it does this information flip on all the profiles at once. I need help figuring out how to have the button only affect the profile it is associated with.
I am still relatively new to coding, so I've mainly been doing research on advice on how to approach this particular situation, but nothing I've found so far has worked.
<mat-card class="bpBuddyCont" *ngFor= "let profile of profileList">
<div>
<ul class="bpBuddies">
<li class="li2">
<div *ngIf="!showHiddenInfo">
<mat-card-title class="specifics">{{profile.dogName}}</mat-card-title>
<mat-card-subtitle class="subtitle">Owner ~ {{profile.ownerFirstName}}</mat-card-subtitle>
<mat-card-subtitle>Member Since {{profile.yearJoined}}</mat-card-subtitle>
</div>
<div class="column4" *ngIf="showHiddenInfo">
<span class="details4">Additional Notes: </span>
<span class="details3">{{profile.additionalNotes}}</span>
</div>
</div>
<button mat-button color="primary" class="btn" (click)="showHiddenInfo = !showHiddenInfo">{{showHiddenInfo ? 'Back' : 'More...'}}</button>
</li>
</ul>
</div>
</mat-card>
You can extend the profile object with
profile.showHiddenInfo and set it as false initially.
For this in your js(most probably the component file) after getting profileList,
profileList.forEach((profile, index) => {
angular.extend(profile, {showHiddenInfo: false});
//not sure about this angular.extend but you need to extend your object here
});
Now when the button is clicked replace showHiddenInfo, i.e.
profile.showHiddenInfo = !profile.showHiddenInfo;
And Replace
*ngIf="showHiddenInfo"
with
*ngIf="profile.showHiddenInfo"
You can do this using one boolean variable for each object, as profile.isExpanded and on click change it as like:
(click)="profile.isExpanded = !profile.isExpanded"
HTML Code:
<mat-card class="bpBuddyCont" *ngFor="let profile of profileList">
<div>
<ul class="bpBuddies">
<li class="li2">
<div *ngIf="!profile.isExpanded">
<mat-card-title class="specifics">{{profile.dogName}}</mat-card-title>
<mat-card-subtitle class="subtitle">Owner ~ {{profile.ownerFirstName}}</mat-card-subtitle>
<mat-card-subtitle>Member Since {{profile.yearJoined}}</mat-card-subtitle>
</div>
<div class="column4" *ngIf="profile.isExpanded">
<span class="details4">Additional Notes: </span>
<span class="details3">{{profile.additionalNotes}}</span>
</div>
<button mat-button color="primary" class="btn" (click)="profile.isExpanded = !profile.isExpanded">{{profile.isExpanded ? 'Back' : 'More...'}}</button>
</li>
</ul>
</div>
</mat-card>
No change in TS file.
WORKING STACKBLITZ

How to show/hide in Angular2

I have a component that show/hide element by clicking a button.
This is my html
<div *ngFor="let history of histories | sortdate: '-dateModified'">
<p><b>{{ history.remarks }}</b> - <i>{{history.dateModified | date:'short'}}</i></p>
<a href="google.com"
[class.datatable-icon-right]="history.$$expanded"
[class.datatable-icon-down]="!history.$$expanded"
title="Expand/Collapse Row"
(click)="toggleExpandRow(history)"></a>
<!-- hide/show this by clicking the button above.-->
<div *ngFor="let step of history.steps; let i = index">
<b>{{i+1}}.</b> {{step}}
<span class="clear"></span>
</div>
<hr />
</div>
and my .ts
toggleExpandRow(row) {
console.log('Toggled Expand Row!', row);
//row
return false;
}
trying to search but, can't find any same sample.
On jquery, I can do this, but on Angular2, I am having hard time to figure this.
There are two options:
1- You can use the hidden directive to show or hide any element
<div [hidden]="!edited" class="alert alert-success box-msg" role="alert">
<strong>List Saved!</strong> Your changes has been saved.
</div>
2- You can use the ngIf control directive to add or remove the element. This is different of the hidden directive because it does not show / hide the element, but it add / remove from the DOM. You can loose unsaved data of the element. It can be the better choice for an edit component that is cancelled.
<div *ngIf="edited" class="alert alert-success box-msg" role="alert">
<strong>List Saved!</strong> Your changes has been saved.
</div>
Use the ngIf in your repeated rows. Create a boolean property called showStep to indicate whether the row should be expanded or not.
<div *ngFor="let step of history.steps; let i = index" ngIf="history.showStep">
<b>{{i+1}}.</b> {{step}}
<span class="clear"></span>
</div>
Then, in your .ts file:
toggleExpandRow(history) {
history.showStep = !history.showStep
//note the same porperty of showStep that is used in your html
}
Extra:
In fact, to save a few lines of codes, you don't even need the toggleExpandRow function at all. You can do it inline in your html:
//other attributes omitted for brevity
<a (click)="history.showStep = !history.showStep">

Knockout Clone Whole Item In foreach

I am trying to clone elements when clicking a button. I was trying to use ko.toJS. On page load it works fine, but when I want clone the items, it is unable to bind the items (like, value, Text, etc.).
Here is the HTML:
<div class="stockItems-inner" data-bind="foreach: StockItems">
<div data-bind="if: Type=='Input'">
<div class="stock_container_input">
<input type="text" data-bind="value: Value" />
</div>
</div>
<div data-bind="if: Type=='Radio'">
<div class="stock_container_control">
<div data-bind="foreach: Options">
<div class="stockLbl">
<input type="radio" data-bind="text: Text, checked:$parent.Value, attr:{'id':Id, 'name': $parent.Text, 'value': Value}" />
<label data-bind="attr:{'for':Id}, text: Text"></label>
</div>
</div>
</div>
</div>
</div>
<div class="addItem">
<button type="button" data-bind="click: CloneItem"><img src="images/add.png" alt="" /></button>
</div>
The View Model:
ConfigurationStockViewModel = function() {
var self = this;
this.StockItems = ko.observableArray();
this.ApplyData = function(data){
self.StockItems(data.Items);
}
this.CloneItem = function(StockItems){
self.StockItems.push(ko.toJS(StockItems));
};
};
When clicking the button, an error is thrown: Unable to process binding. I am using JSON data for binding.
Not exactly sure what end result you want without working code, but sounds like you want to clone the last item in array and add to array?
If so, I think you have an error - your add button click binding will never pass anything to the function you defined, since it is outside the foreach. You need something like this:
this.CloneItem = function() {
var toClone = self.StockItems()[self.StockItems().length - 1]
self.StockItems.push(toClone);
};
Here is a simplified example without radio buttons, etc:
http://jsfiddle.net/5J47L/