How to show/hide in Angular2 - html

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">

Related

Change elements of one specific div of *ngFor

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>

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 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 switch between Grid and List view using Typescript Angular4

Working in an Angular4 application ,In this I need to have a UI which contains the Grid view and List View options for displaying products .
I have designed the UI but I need to do some magics in Typescript,So I looking for SO.
I have referred some other examples nothing is worked for me .
Please refer my Stackblitz File : https://stackblitz.com/edit/angular-s8oogm?file=app%2Fapp.component.html
Where I have the HTMl,CSS and I want to enable the functions for switch between List and Grid View.
When I switch to list view I need to show the product like the below image ,For that my stackblitz file I have done the CSS but I don't know it's right or wrong .
Grid View
List View
Thanks.
you can create 2 nested components AppGridProduct and AppListProduct and call show them based on your display mode and send data to each component using Input:
<div class="btn-group pull-right">
<button class="btn btn-white" type="button"(click)="onDisplayModeChange(1)"
[ngClass]="{'btn-primary active': displayMode === 1}" >
<i class="fa fa-th"></i>
</button>
<button class="btn btn-white" type="button" (click)="onDisplayModeChange(2)"
[ngClass]="{'btn-primary active': displayMode === 2}" >
<i class="fa fa-list"></i>
</button>
</div>
<!-- grid -->
<div class="row" *ngIf="displayMode === 1">
<app-grid-container *ngFor='let product of productsList' [product]="product"></app-grid-container>
</div>
<!-- List -->
<div class="row" *ngIf="displayMode === 2">
<app-list-container *ngFor='let product of productsList' [product]="product></app-list-container>
</div>
and in your component.ts
onDisplayModeChange(mode: number): void {
this.displayMode = mode;
}
add this to your css:
button.active {
color: green;
}
add this insted of class='card' [ngClass]="isCard?'card':'list'"
and in your controller switch isCard flag based on the user input
You need to implement card and list classes and their child classes based on the ui requirements, also you can use isCard flag to show hide elements specific for grid and list view.

Drop Down Menu Categories / Sub Categories

What I am trying to do is have a drop down menu divided. In this example there are Five Options how can I split the drop down into categories? For example option 1 and 2 pop out of the environment category and option 3 and 4 sports category and 5 college category? http://jsfiddle.net/fc3550sk/
For example:
Drop down: Please Select when you click it Menus will be Environment, Sports, Colleges..
Then hover over Environment and it will let you choose from option 1 or 2... or hover over sports and it will let you chose from 3 or 4 and so on..
This is what I have so far:
<select name="SPECIAL" id="SPECIAL">
<option>Please Select</div>
<option data-img="/images/img/AnimalFriend.png" value="1">AnimalFriend</option>
<option data-img="/images/img/Aquaculture.png" value="2">Aquaculture</option>
<option data-img="/images/img/ProtectOurOceans.png" value="3">Protect Our Oceans</option>
<option data-img="/images/img/ConserveWildlife.png" value="4">Conserve Wildlife</option>
</select>
<!-- Modal -->
<div class="modal fade" id="modal_special" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Specialty Plate</h4>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary accept">Accept</button>
</div>
</div>
</div>
</div>
$(function() {
$('#SPECIAL').on('change', function() {
if ($('option:selected', this).is('[data-img]')) {
$('#modal_special').find('.modal-body').html('<p>Image will go here:</p>')
.append('<img alt="coming soon" src="' + $('option:selected', this).data('img') + '"/>')
.end().modal('show');
}
});
$('.accept').on('click',function() {
//do something
$('#modal_special').modal('hide');
});
});
Any help would be greatly appreciated!!
I don't know of a way to attach a "hover" event listener to a standard drop-down menu, but it's not too much work to implement your own custom drop-down with jquery, html and css.
Custom Drop-down Advantage #01
You get to assign as many custom values to each entry as you want.
In your example, you have "Specialty Plates", and you may want to assign a price, a special code assigned to that plate, an image assigned to that plate, and so on. With an HTML/jQuery version, you can create your custom drop-downs with simple <span> tags like this:
<span data-code="SPRT01" data-image="" data-price="34.00">Sports 01</span>
<span data-code="SPRT02" data-image="" data-price="35.00">Sports 02</span>
<span data-code="SPRT03" data-image="" data-price="36.00">Sports 03</span>
Notice how each entry has three custom values assigned to it: data-code, data-image, and data-price. If you use an html drop-down, you don't have as much freedom. There are ways to extend the values associated with a standard drop-down, but getting at the values is messy, and you will still not have access to the hover behavior your features require.
Custom Drop-down Advantage #02
You can actually use the hover behavior in any way you want.
In your example, you want the "submenus" to show up when certain values in your drop-down are selected, but as far as I know, there isn't a way to gain access to the values that are "hovered" in a standard drop-down, and looking for an HTML-only solution just doesn't exist, so you would have to use javascript in one way or another.
Using jQuery, you can easily get to the values in your custom drop-down elements like this:
$("span").hover(
function(){
var text = $(this).text();
console.log("You have hovered on: ", text);
},
function(){
// You have hovered off the span
}
);
My Solution to Your Problem
Putting these ideas into practice, I put together a simple demo of how you can create a custom drop-down using your applications parameters.
You can review a jsfiddle of the demo here.
The Basic idea is that you create a hierarchy in html with the structure of your Top-level options (Environment, Sports, Colleges) in the div .drop_down_scroll_container, and you place all your sub-level divs (Environment 01, Environment 02, etc) below that div in a div classed .dropdown-subcategory. Where the magic happens, is that javascript looks up the index of the top-level option, and then reveals the dropdown-subcategory with that same index.
For example, in the following snippet of html, you can see the index positions of each of the spans within the drop_down_scroll_container div:
<div class="drop_down_scroll_container">
<span>Environment</span> <!-- index 0 -->
<span>Sports</span> <!-- index 1 -->
<span>Colleges</span> <!-- index 2 -->
</div>
So then, when you hover over any of those Top-level options (Environment, Sports, Colleges) you can ask jQuery to reveal the corresponding submenu div, which are sitting below the .drop_down_scroll_container div in div containers with a class of .dropdown-subcategory
<div id="dropdown" class="specialtyPlatesCategories">
<div class="selectHeader">Click to Select Plates:</div>
<!-- THIS IS WHERE YOU WILL PUT YOUR TOP-LEVEL OPTIONS -->
<div class="drop_down_scroll_container">
<span>Environment</span>
<span>Sports</span>
<span>Colleges</span>
</div>
<!-- THIS DIV IS AT INDEX 0 of: #dropdown.dropdown-subcategory -->
<!-- Will fade in when the drop_down_scroll_container index 0 is hovered -->
<div id="env_subcategories" class="dropdown-subcategory">
<span data-code="ENV01" data-image="" data-price="31.00">Environment 01</span>
<span data-code="ENV02" data-image="" data-price="32.00">Environment 02</span>
<span data-code="ENV03" data-image="" data-price="33.00">Environment 03</span>
</div>
<!-- THIS DIV IS AT INDEX 1 of: #dropdown.dropdown-subcategory -->
<!-- Will fade in when the drop_down_scroll_container index 1 is hovered -->
<div id="sports_subcategories" class="dropdown-subcategory">
<span data-code="SPRT01" data-image="" data-price="34.00">Sports 01</span>
<span data-code="SPRT02" data-image="" data-price="35.00">Sports 02</span>
<span data-code="SPRT03" data-image="" data-price="36.00">Sports 03</span>
</div>
<!-- THIS DIV IS AT INDEX 2 of: #dropdown.dropdown-subcategory -->
<!-- Will fade in when the drop_down_scroll_container index 2 is hovered -->
<div id="colleges_subcategories" class="dropdown-subcategory">
<span data-code="COLL01" data-image="" data-price="37.00">Colleges 01</span>
<span data-code="COLL02" data-image="" data-price="38.00">Colleges 02</span>
<span data-code="COLL03" data-image="" data-price="39.00">Colleges 03</span>
</div>
</div>
If none of that made any sense, here is another way of looking it at:
When the first item in the .drop_down_scroll_container is hovered, jQuery looks for the first instance of a .dropdown-subcategory below it. When the second item in the .drop_down_scroll_container is hovered, then jQuery will reveal the second instance of the .dropdown-subcategory, and so on. This lets you build as many options as you want, without having to worry about giving everything specific names, only the order matters in this case. So when the "Environment" option (who's index equals 0) is hovered, the .dropdown-subcategory with an index of 0 will show. That is the basic idea.
So now for the jQuery that puts it all together:
$(document).ready(function(){
// When the header for the custom drop-down is clicked
$(".selectHeader").click(function() {
// cache the actual dropdown scroll container
var dropdown = $(this).parent().find(".drop_down_scroll_container");
// Toggle the visibility on click
if (dropdown.is(":visible")) {
dropdown.slideUp();
$(this).parent().find(".dropdown-subcategory").fadeOut();
} else {
dropdown.slideDown();
}
});
// When a top-level menu item is hovered, decide if its
// coorespnding submenu should be visible or hidden
$(".drop_down_scroll_container span").hover(
// hover on
function() {
// Remove the "highlighted class from all other options
$(this).parent().find("span").removeClass("highlighted").removeClass("selected");
$(this).addClass("highlighted").addClass("selected");
// Get the index of the hovered span
var index = $(this).index();
// Use the hovered index to reveal the
// dropdown-subcategory of the same index
var subcategorydiv = $(this).parent().parent().find(".dropdown-subcategory").eq(index);
hideallSubmenusExceptMenuAtIndex($(this).parent().parent(), index);
subcategorydiv.slideDown();
},
// hover off
function() {
if (!$(this).hasClass("highlighted")) {
var index = $(this).index();
var subcategorydiv = $(this).parent().parent().find(".dropdown-subcategory").eq(index);
subcategorydiv.slideUp();
}
});
// Hide all submenu items except for the submenu item at _index
// This will hide any of the previously opened submenu items
function hideallSubmenusExceptMenuAtIndex(formElement, _index) {
formElement.find(".dropdown-subcategory").each(
function(index) {
if (_index != index) {
$(this).hide();
}
}
);
}
// When any menu item is hovered
$("span").hover(
function() {
$(".hoveredOver").text($(this).text());
},
function() {
$(".hoveredOver").text("");
}
);
// When a sub-menu option is clicked
$(".dropdown-subcategory span").click(function() {
$(".dropdown-subcategory span").removeClass("selected");
$(".clickedOption").text($(this).text());
$(this).addClass("selected");
$(this).parent().parent().find(".selectHeader").text($(this).text());
closeDropDown($(this).parent().parent());
showSpecialPlateModal($(this).text(), $(this).attr("data-image"), $(this).attr("data-price"), $(this).attr("data-code"));
});
// Close the dropdowns contained in divToSearch
function closeDropDown(divToSearch) {
divToSearch.find(".drop_down_scroll_container").fadeOut();
divToSearch.find(".dropdown-subcategory").fadeOut();
};
// Populate and Launch the bootstrap Modal Dialog Specialty Plates
function showSpecialPlateModal(name, image, price, code) {
$('#modal_special').find('.modal-body')
.html('<h2>' + name + '</h2>')
.append('<br/>Special Plate Code: <span class="code">' + code + '</span><br/>')
.append('<p>Image will go here:</p><br/><img alt="" src="' + image + '"/>')
.append('<br/><br/>Price: <span class="price">' + price + '</span><br/>')
.end().modal('show');
}
// When the modal "Accept" button is pressed
$('.accept').on('click', function() {
var modal_element = $('#modal_special');
var name = modal_element.find("h2").text();
var price = modal_element.find("span.price").text();
var code = modal_element.find("span.code").text();
$('#modal_special').modal('hide').end(alert(name + " was selected for a price of " + price));
});
});
Note: There may already be some open-source solutions that take care of this problem in a more elegant fashion. But this was my approach at solving an issue like this. As you can see, it only takes a little bit of setup to get going. You can easily control the styling of the drop-down in css, and you can extend this to do anything you want.
Again, you can review a jsfiddle to see all of this code in action here.
Hope this helps!
I am not sure if this is exactly what your were looking for but you could try something like this:
<select name="SPECIAL" id="SPECIAL">
<option>Please Select</div>
<optgroup label="Environmental">
<option
data-img="/images/img/AnimalFriend.png"
value="1">AnimalFriend</option>
<option
data-img="/images/img/Aquaculture.png"
value="2">Aquaculture</option>
</optgroup>
<optgroup label="Sports">
<option
data-img="/images/img/ProtectOurOceans.png"
value="3">Protect Our Oceans</option>
<option
data-img="/images/img/ConserveWildlife.png"
value="4">Conserve Wildlife</option>
</optgroup>
</select>