I need to achieve the responsive page as shown below in the image.
I have created something like this. But my mat-card gets cut or hidden in the tile , when I reduce the browser size. I managed to create this:
Where am I going wrong? Below is my code.
header.component.html
<div fxLayout="column" fxLayout.xs="column">
<mat-toolbar color="primary" >
<button mat-button (click)="side_nav.open()">
<mat-icon>menu</mat-icon>
</button>
<img src="../assets/weather_images/logo.png" style="width: 35px;">
<span> Minimus </span>
<span class="header_text"></span>
<span>TODAY</span>
<span class="header_text"></span>
<span>light</span>
<mat-slide-toggle [checked]="isDarkTheme | async" (change)="toggleDarkTheme($event.checked)"></mat-slide-toggle>
<span>dark</span>
</mat-toolbar>
<mat-sidenav-container [ngClass]="{'dark-theme': isDarkTheme | async}" >
<mat-sidenav #side_nav style="height: 100%;width: 200px;">
<br><br><div class="m"><span routerLink='' (click)="side_nav.close();" > Home </span></div><br><br><br>
<div class="m"><span routerLink='/search-cities' (click)="side_nav.close();">Add City</span></div>
</mat-sidenav>
<mat-sidenav-content><br>
<div [#fade] = "prepareRoute(o)" [#flyInOut] = "prepareRoute(o)">
<router-outlet #o="outlet"></router-outlet>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
</div>
addciyt .component .html
<div>
<mat-grid-list [cols]="breakpoint" (window:resize)="onResize($event)" gutterSize="30px" [ngClass]="{'dark-theme': isDarkTheme | async}">
<mat-grid-tile>
<mat-card class="card_style" [ngClass]="{'dark-theme': isDarkTheme | async}" routerLink="/search-cities" #slideInOut>
<mat-card-title class="card_title" [ngClass]="{'dark-theme': isDarkTheme | async}">ADD CITY</mat-card-title><br>
<img src="../assets/weather_images/plus.png" alt="Plus image" width="150px" class="image_style">
<img mat-card-image src="../assets/weather_images/1.png" height="260px">
</mat-card>
</mat-grid-tile>
<mat-grid-tile *ngFor = "let v of value">
<mat-card class="card_style" [routerLink]="['/details',v.city_name]" #fade>
<mat-card-title class="card_title">
{{value ? (v.city_name).toUpperCase() : ''}}
</mat-card-title><br>
<div *ngIf = "v.des === 'Clouds'" style="text-align: center;">
<img src= "../assets/weather_images/cloudy.png" alt="cloudy" class="image">
</div>
<div *ngIf = "v.des === 'Rain'" style="text-align: center;">
<img src= "../assets/weather_images/raining.png" alt="raining" class="image">
</div>
<div *ngIf = "v.des === 'Clear'" style="text-align: center;">
<img src= "../assets/weather_images/sunny.png" alt="clear" class="image">
</div>
<div *ngIf = "v.des === 'Strom'" style="text-align: center;">
<img src= "../assets/weather_images/strom.png" alt="strom" class="image">
</div>
<div *ngIf = "v.des === 'Snow'" style="text-align: center;">
<img src= "../assets/weather_images/snowing.png" alt="strom" class="image">
</div>
<mat-card-content>
<div>
<p class="temp">{{value ? (v.temp - 273.15).toFixed(2) : ''}}℃</p>
</div>
<p class="main">{{value ? (v.des).toUpperCase() : ''}}</p>
<p style="margin-left: 35px; font-size: 16px;">Temp_min Temp_max</p>
<p class="temp_min">{{value ? (v.temp_min - 273.15).toFixed(2) : ''}}℃<span class="temp_max">{{value ? (v.temp_max - 273.15).toFixed(2) : ''}}℃</span></p>
</mat-card-content>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
</div>
addcity.component.ts
import { Component, OnInit } from "#angular/core";
import { Observable } from "rxjs";
import { ThemeService } from "../services/theme.service";
import { WeatherService } from "../services/weather.service";
import { AngularFireDatabase } from "angularfire2/database";
import { slideInOut, fade } from "../animation";
import { FormControl } from '#angular/forms';
import { map, startWith } from 'rxjs/operators';
#Component({
selector: "app-addcity",
templateUrl: "./addcity.component.html",
styleUrls: ["./addcity.component.scss"],
animations: [
slideInOut,
fade
]
})
export class AddcityComponent implements OnInit {
value: Array<any> = [];
cities: Array<any>;
isDarkTheme: Observable<boolean>;
myControl = new FormControl();
options: string[] = ['One', 'Two', 'Three'];
filteredOptions: Observable<string[]>;
control = new FormControl();
streets: string[] = ['Champs-Élysées', 'Lombard Street', 'Abbey Road', 'Fifth Avenue', 's','d','f','y','u','h','l'];
filteredStreets: Observable<string[]>;
name = '';
breakpoint:number;
constructor(
private themeService: ThemeService,
private db: AngularFireDatabase,
private weatherService: WeatherService
) {
db.list("/user/cities")
.valueChanges()
.subscribe((cities) => {
this.cities = cities;
for (let c of cities) {
this.weatherService.getcities(c['name']).subscribe(value => {
const temp = value["main"].temp;
const temp_min = value["main"].temp_min;
const temp_max = value["main"].temp_max;
const des = value["weather"][0].main;
const city_name = c['name'];
const a = {
temp,
temp_min,
temp_max,
des,
city_name
};
this.value.push(a);
});
}
});
console.log(this.name);
}
ngOnInit() {
this.isDarkTheme = this.themeService.isDarkTheme;
this.breakpoint = (window.innerWidth <= 400) ? 1 : 2;
}
onResize(event) {
this.breakpoint = (event.target.innerWidth <= 400) ? 1 : 2;
}
}
I tried a lot but nothing seems to work.
#DHEERAJ to make your page responsive, you can use different CSS techniques, you can also use the #angular/flex-layout in combination with Angular Material
Find here the Details of #angular/flex-Layout and FlexLayout Examples
Related
My task: The received value from service 1 or 2, depending on the value, change the styles in the html component. Using the ng-switch directive, I expect to compare the value received from the object with the specified template value. Styles are not applied. The main problem is that the styles are not applied
My component:
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, Self } from '#angular/core';
import { ConfigService, IProductListItem, SliderValueOptions } from 'common-modules';
import { Router } from '#angular/router';
import { debounceTime, filter, takeUntil, tap } from 'rxjs/operators';
import { NgOnDestroy } from '../../core/services/destroy.service';
import { BehaviorSubject } from 'rxjs';
import { OnInit, OnDestroy } from '#angular/core';
#Component({
selector: 'app-product-item',
templateUrl: './product-item.component.html',
styleUrls: ['./product-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [NgOnDestroy],
})
export class ProductItemComponent implements OnInit, OnDestroy {
#Input() product: IProductListItem;
#Input() doubleClickEnabled: boolean;
// tslint:disable-next-line:no-output-on-prefix
#Output() onAddToCart = new EventEmitter<any>();
themeProperties: number;
visibility: boolean = false;
constructor(private _router: Router, private _config: ConfigService, #Self() private onDestroy$: NgOnDestroy) {}
ngOnInit() {
this._config.marketplaceConfig.pipe(takeUntil(this.onDestroy$)).subscribe((config) => {
this.themeProperties = config.structure?.theme;
});
}
}
My html:
<mat-card class="card">
<div [ngSwitch]="themeProperties">
<ng-template *ngswitchcase="2">
{{ themeProperties }}
<mat-card id="cardbackground">
<a class="card__link" (click)="redirectToProduct(product)" (dblclick)="doubleClicked(product)">
<div
style="display: none"
class="card__promo"
*ngIf="product.priceWithDiscount && product?.promoIndividual?.percentDiscount"
>
-{{ product?.promoIndividual?.percentDiscount }}%
</div>
<!-- <b2b-modern-image mat-card-image [src]="product.photos[0]"></b2b-modern-image> -->
<img class="mat-card-image" [src]="product.photos" alt="" />
<mat-card-content class="card__content" [class.has-padding-top]="product && product['discount']">
<div class="super-sale">супер скидка</div>
<div *ngIf="product && product['discount']" class="discount">-{{ product['discount'] }}%</div>
<div
*ngIf="product && product.promoIndividual && product?.promoIndividual?.percentDiscount"
class="discount"
>
-{{ product?.promoIndividual?.percentDiscount }}
%
</div>
<ng-template #defaultPrice>
<!-- <span class="price">{{product.price}} ₽</span>-->
</ng-template>
<div class="rating">
<ngx-stars color="#ffd700" [readonly]="true" [initialStars]="product.rating || 0"> </ngx-stars>
<span class="ml-3">{{ product.views || 0 }} отзывов</span>
</div>
<h3 class="name wrap-two-line" [matTooltip]="product?.feed" matTooltipPosition="above">
{{ product | localize: 'name' }}
</h3>
<div class="а">
<div
class="d-flex align-items-center"
*ngIf="product.priceWithDiscount && product.priceWithDiscount != product.price; else defaultPrice"
>
<span class="price old">{{ product.price }}₽</span>
</div>
<p class="price">{{ (product.priceWithDiscount || 0).toFixed(1) }}₽</p>
</div>
</mat-card-content>
</a>
<mat-card-footer class="card__footer">
<a routerLink="/confirm-order" [queryParams]="{ products: product.id }" mat-raised-button color="primary">
Купить сейчас
</a>
<button mat-button color="primary" (click)="addToCart(product)">
<mat-icon>add_shopping_cart</mat-icon>
</button>
</mat-card-footer>
</mat-card>
</ng-template>
</div>
</mat-card>
change component to:
themeProperties$: Observable<number>;
...
ngOnInit() {
this.themeProperties$ = this._config.marketplaceConfig.pipe(map((config) => config.structure?.theme))
}
change template to:
<div [ngSwitch]="themeProperties$ | async">
<ng-container *ngSwitchCase="2">
....
</ng-container>
issues:
casing wrong on ngSwitchCase directive
OnPush change detection not running correctly, async pipe resolves
ng-template doesn't render to DOM. it's a template for use elsewhere. use ng-container instead.
The spelling of the template switch statement is case sensitive, should be *ngSwitchCase.
Also the ng-template does not work in this case, you need to use ng-container
So please change your statements to this layout, and all should work:
<ng-container *ngSwitchCase="2">
also because you are using ChangeDetectionStrategy.OnPush you need to trigger the change detection manually for the ngSwitch.
Here is a working example.
constructor(private _router: Router, private _config: ConfigService, #Self() private onDestroy$: NgOnDestroy, private cdr: ChangeDetectorRef) {}
ngOnInit() {
this._config.marketplaceConfig.pipe(takeUntil(this.onDestroy$)).subscribe((config) => {
this.themeProperties = config.structure?.theme;
this.cdr.detectChanges(); // <=== here, after setting the value
});
}
I am building an Angular Movie DB, the two components I am working with are the "search-movie" component and the "single-view" component. The "search-movie" component displays a list of movies, the "single-view" component shows further details of a given movie.
I would like it so that when I click on a movie from the list in the "search-movie" component, the page renders the "single-view" component for that movie.
I have managed to set this up so that navigating to the "single-view" path with a movie id (i.e. /movie/tt4425200) directly from the URL, correctly loads up the info for that movie by it's ID, so that's all correctly set up.
I just can't seem to connect the clicking of a movie in the "search-movie" component, to then successfully navigate to the correct "single-view" path. So using the example above, clicking on the relevant movie loads up the "single-view" component with the URL path /movie/tt4425200.
I'm sure that this is a case of using #Input to communicate between the two components, but I just can't figure it out.
search-movie.component.ts:
import { Component, OnInit, Input } from '#angular/core';
import { FormControl } from '#angular/forms';
import { DataService } from '../data.service';
#Component({
selector: 'app-search-movie',
templateUrl: './search-movie.component.html',
styleUrls: ['./search-movie.component.css']
})
export class SearchMovieComponent implements OnInit {
searchControl = new FormControl('');
movieResults: any = [];
constructor(private data: DataService) { }
ngOnInit() {}
/* GET request */
getData(event) {
const film = event.target.value;
this.data.searchFilm(film)
.subscribe( (res) => {
res = this.movieResults = res;
console.log(res);
});
}
}
search-movie.component.html:
<div class="container">
<h1 class="is-size-3">Find your favorite movies...</h1>
<form (ngSubmit)="onSubmit()">
<input
type="text"
(keyup)="getData($event)"
placeholder="Start typing..."
[formControl]="searchControl" />
</form>
{{searchControl.value}}
</div>
<div class="container">
<ul>
<li id="list-item" *ngFor="let x of movieResults; let i = index;">
<img [src]="x.Poster" onerror="this.src='../assets/images/default-poster.jpg'">
<p id="movie-title" class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
</li>
</ul>
</div>
single-view.component.ts:
import { Component, OnInit, Input } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { DataService } from '../data.service';
#Component({
selector: 'app-single-view',
templateUrl: './single-view.component.html',
styleUrls: ['./single-view.component.css']
})
export class SingleViewComponent implements OnInit {
singleDetails: any = {};
constructor(
private data: DataService,
private route: ActivatedRoute) { }
ngOnInit() {
/** GENERATE FILM DETAILS BY movie/id where id is the imdbID */
const id = this.route.snapshot.paramMap.get('id');
this.data.moviebyID(id)
.subscribe( (res) => {
res = this.singleDetails = res;
});
}
}
single-view.component.html:
<div class="container singleDisplayContainer">
<div class="columns is-mobile">
<div class="column" id="poster-column">
<img id="poster" [src]="singleDetails.Poster" [alt]="singleDetails.Title" onerror="this.src='../assets/images/default-poster.jpg'">
</div>
<div id="info-column" class="column">
<div class="columns">
<div class="column is-three-fifths">
<h1 class="is-size-3">{{singleDetails.Title}} <span class="is-size-4">({{singleDetails.Year}})</span> </h1>
<p style="font-size: 14px"> {{singleDetails.Rated}} | {{singleDetails.Runtime}} | {{singleDetails.Genre}} | {{singleDetails.Released}} </p>
</div>
<div class="column">
<div class="columns">
<div class="column is-one-third">
<img id="star-rating" width="50px" src="../../assets/images/star-rating.png" alt="{{singleDetails.Title}}">
</div>
<div class="column">
<p style="font-size: 2em"> {{singleDetails.imdbRating}}<span style="font-size: 12px">/10</span></p>
<p>{{singleDetails.imdbVotes}}</p>
</div>
</div>
</div>
</div>
<br>
<p>Plot: {{singleDetails.Plot}} </p>
<br>
<p>Directed by: {{singleDetails.Director}} </p>
<br>
<p>Writers: {{singleDetails.Writer}} </p>
<br>
<p>Actors: {{singleDetails.Actors}} </p>
<br>
<p onerror="this.style.display='none'">Box office: {{singleDetails.BoxOffice}} </p>
</div>
</div>
</div>
In Your UL -> LI, add routerLink property and pass the movie id as the second param
[routerLink]="['/movie/,x.movieId]">
<ul>
<li id="list-item" *ngFor="let x of movieResults; let i = index;" [routerLink]="['/movie/,x.movieId]">
<img [src]="x.Poster" onerror="this.src='../assets/images/default-poster.jpg'">
<p
id="movie-title"
class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
</li>
</ul>
Looks like you have everything set up, all you need to do is navigate to single-view on click of the movie.
search-movie.component.ts
showDetails(id : string) {
this.router.navigate(['movie',{ id }]);
}
search-movie.component.html
<!-- in showDetails you will pass id of the current movie while looping -->
<li id="list-item" *ngFor="let x of movieResults; let i = index;" (click)="showDetails(x.id)">
<img
[src]="x.Poster"
onerror="this.src='../assets/images/default-poster.jpg'"
>
<p
id="movie-title"
class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
</li>
This will navigate to single-view page. is this what you want right?
or you need to load single-view in the same page as the list?
I have a bunch of cards using ngFor with user's information. There is a button inside the card that will display travel information for that specific user.
I created a div with the initial state display: none. I thought about using ngStyle to bind the display: block property upon click, but the problem is that all the divs are getting displayed and not only the specific one I need.
Any suggestions on how I can do this?
html
<div class="col s12 m6 l4" *ngFor="let student of students; let i = index">
<i class="material-icons" (click)="showBox()">access_alarm</i>
<div class="travel-info" [ngStyle]="{'display': boxDisplay == true ? 'block' : 'none'}" >
<app-travel-info ></app-travel-info>
</div>
</div>
ts
boxDisplay = false;
showBox() {
this.boxDisplay = true;
}
The problem is you only have one variable that is set for all of them.
You will want to refactor showBox to be something like this.
TS
this.boxDisplay = this.students.map(s => false);
showBox(index) {
this.boxDisplay[index] = true;
}
HTML
<div class="col s12 m6 l4" *ngFor="let student of students; let i = index">
<i class="material-icons" (click)="showBox(i)">access_alarm</i>
<div class="travel-info" [ngStyle]="{'display': boxDisplay[i] == true ? 'block' : 'none'}" >
<app-travel-info ></app-travel-info>
</div>
</div>
If it were me I would use ngIf instead of the ngStyle.
<div class="col s12 m6 l4" *ngFor="let student of students; let i = index">
<i class="material-icons" (click)="showBox(i)">access_alarm</i>
<div class="travel-info" *ngIf="boxDisplay[i]" >
<app-travel-info ></app-travel-info>
</div>
</div>
You need to have a property display with each elements of the students array and then enable/disable based on the index,
<div class="col s12 m6 l4" *ngFor="let student of students; let i = index">
<i class="material-icons" (click)="showBox(student)">access_alarm</i>
<div class="travel-info" [ngStyle]"{'display': student.boxDisplay == true ? 'block' : 'none'}" >
<app-travel-info ></app-travel-info>
</div>
</div>
showBox(student:any) {
student.boxDisplay = true;
}
You can use #ViewChildren. I give you this example:
Your HTML:
<div class="student-container" *ngFor="let s of students; let i = index">
<span>Name: {{s.name}} - Index: {{i}}</span>
<div class="student-box" #boxes>
<span>Hey! I'm opened.</span>
<span>My Secret Number is: {{s.secretNumber}}</span>
</div>
<button (click)="toggleBox(i)">Click Me!</button>
</div>
Your Component:
import { Component, ViewChildren, QueryList, ElementRef } from "#angular/core";
#Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
#ViewChildren("boxes") private boxes: QueryList<ElementRef>;
students = [
{ name: "Peter", secretNumber: "88" },
{ name: "Laura", secretNumber: "45" },
{ name: "Paul", secretNumber: "13" }
];
toggleBox(index) {
let nativeElement = this.boxes.toArray()[index].nativeElement;
nativeElement.style.display =
nativeElement.style.display === "none" || !nativeElement.style.display
? "block"
: "none";
}
}
Your CSS:
.student-container {
background: lightblue;
margin: 10px;
padding: 10px;
}
.student-box {
display: none;
}
https://codesandbox.io/s/zwqoxp583x
I have a search form in an Angular app that I've written. You can type in a word or phrase and when you hit search you are given the results with the option to toggle between a standard list view (formatted to look like the results in a google search) or in a card view. The list view is the default setting and the user can toggle to the card view.
I handle the toggling via a mat-button-toggle-group and on (change) of the mat-button-toggle, I set a boolean variable that is used by my markup to determine which view to show. This all works brilliantly if I'm switching from the default view (list) to the card view. But when I want to switch back to the list view from the card view, nothing happens. I've added logging to the (change) event so I know the variable is being reset but nothing is happening. Below is my code:
search.component.html
<div class="search-fields page-content">
<mat-form-field appearance="outline" disabled="false">
<mat-label>Keyword(s)</mat-label>
<input #txtSearch matInput type="search" placeholder="Search Phrase" [(ngModel)]="this.searchPhrase" (keyup.enter)="onSearchClick()">
<button mat-button *ngIf="value" matSuffix mat-icon-button aria-label="Clear" (click)="this.searchPhrase=''">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<button mat-raised-button color="primary" (click)="onSearchClick()">Search</button>
</div>
<div *ngIf="dataModel" class="container page-content">
<div class="full-width">
<mat-button-toggle-group value="false">
<mat-button-toggle selected="true" value="false" (change)="onToggleClick($event.value)" matTooltip="View List">
<mat-icon>view_list</mat-icon>
</mat-button-toggle>
<mat-button-toggle value="true" (change)="onToggleClick($event.value)" matTooltip="View Tiles">
<mat-icon>view_comfy</mat-icon>
</mat-button-toggle>
</mat-button-toggle-group>
</div>
<span class="query-info">Showing {{ getBeginHits() }} - {{ getEndHits() }} of {{ this.dataModel.totalHits }} results </span>
<div *ngIf="!isTile" class="result-detail">
<div *ngFor="let page of dataModel.pages">
<div class="full-width">
<h3>{{ page.title }}</h3>
</div>
<div class="full-width matches-detail">
<span>{{ page.matchesString }}</span>
</div>
<div class="full-width result-snippet" [innerHTML]="page.textSnippet">
</div>
</div>
</div>
<mat-grid-list cols="5" *ngIf="isTile">
<mat-grid-tile *ngFor="let page of dataModel.pages" [colspan]="1" [rowspan]="1">
<mat-card >
<mat-card-header>
<mat-card-title><strong>{{ page.title }}</strong></mat-card-title>
</mat-card-header>
<img mat-card-image src="{{ this.imageBase + page.id.trim() + '.jpg' }}" alt="Photo of page" />
<mat-card-content>
<ul>
<li *ngFor="let s of page.matchesArray">{{ s }}</li>
</ul>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button color="primary" routerLink="{{ '/page/' + page.id.trim() }}">VIEW</button>
</mat-card-actions>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
<div class="align-center">
<button mat-icon-button [disabled]="this.currentIndex == 1" (click)="onNavClick(this.currentIndex - 1)" >
<mat-icon aria-label="Previous">navigate_before</mat-icon>
</button>
<ng-container *ngFor="let item of this.getPageArray(); let i = index;">
<button mat-mini-fab color="primary" (click)="onNavClick(i + 1)">{{ i + 1 }}</button>
</ng-container>
<button mat-icon-button [disabled]="this.currentIndex == this.dataModel.totalPageResults" (click)="onNavClick(this.currentIndex + 1)">
<mat-icon aria-label="Next">navigate_next</mat-icon>
</button>
</div>
</div>
search.component.ts
import {Component, ElementRef, OnInit, ViewChild} from '#angular/core';
import {ActivatedRoute} from '#angular/router';
import {PageService} from '../service/page.service';
import {PageResult} from '../../shared/models/page-result.model';
import { environment } from '../../../environments/environment';
import * as _ from 'lodash';
import {_sanitizeHtml} from '#angular/core/src/sanitization/html_sanitizer';
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {
searchPhrase: string;
isTile: boolean;
dataModel: PageResult;
imageBase: string = environment.imageUrl + 'thumbs/';
currentIndex: number;
constructor(private route: ActivatedRoute, private pageService: PageService) { }
ngOnInit() {
}
getPageArray(): any[] {
return new Array(this.dataModel.totalPageResults);
}
getBeginHits(): number {
return ((this.dataModel.currentIndex * this.dataModel.resultLimit) - this.dataModel.resultLimit + 1);
}
getEndHits(): number {
return (this.dataModel.currentIndex * this.dataModel.resultLimit);
}
onNavClick(index: number) {
this.currentIndex = index;
this.pageService.search(this.searchPhrase, index, 20)
.subscribe(
data => this.dataModel = data,
error => console.log(error),
);
}
onToggleClick(value: boolean) {
this.isTile = value;
console.log('isTile: ' + this.isTile.toString());
}
onSearchClick() {
this.currentIndex = 1;
this.isTile = false;
this.pageService.search(this.searchPhrase, 1, 20)
.subscribe(
data => this.dataModel = data,
error => console.log(error),
);
}
}
If you look at the onToggleClick() method, the logging there tells me that the isTile variable is definitely being changed. It's just not triggering a change to the variable. Furthermore, if I try to use the paging buttons, the view stays in Tile mode even if I've flipped tile mode off. Can anyone spot what I'm doing wrong?
Did you try wrapping
<mat-grid-list cols="5" *ngIf="isTile">
in a <div *ngIf="isTile">
as you do for full width ? maybe *ngIf is not working in mat-grid-list, but should work
I have an array of Google Map Embed API URLs. However, when iterating over each item and binding them to the source of an iFrame.
I could use the following.
constructor(private sanitizer: DomSanitizationService) {
this.url = sanitizer.bypassSecurityTrustResourceUrl('https://www.google.com/maps/embed/v1/place?key=KEY&q=365 Badger Ave, Newark, New Jersey 07112');
}
But, I would have to do this for each item and I can't do so since I receive the array from an external source that updates.
How could I bypass the security for each of my URLs?
Here's app.component.ts
import { Component, Pipe } from '#angular/core';
import { DomSanitizationService } from '#angular/platform-browser';
#Pipe({name: 'secureUrl'})
export class Url {
constructor(private sanitizer:DomSanitizationService){
this.sanitizer = sanitizer;
}
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url).changingThisBreaksApplicationSecurity;
}
}
#Component({
selector: 'my-app',
pipes: [Url],
template: `
<div class="container">
<div style="padding-top: 20px">
<div class="row" *ngFor="let row of rows">
<div *ngFor="let event of row">
<div class="col s12 m6 l4">
<div class="card hoverable">
<div class="card-image waves-effect waves-block waves-light">
<img height="300" class="activator" [src]="event.thumbnail">
</div>
<div class="card-content">
<span class="card-title activator grey-text text-darken-4">{{event.title}}</span>
<p><a class="activator">Hosted by {{event.host.data.first_name}} {{event.host.data.last_name}}</a></p>
</div>
<div class="card-action grey lighten-2">
<a class="blue-grey-text lighten-3">Details</a>
<a class="blue-grey-text lighten-3">Join</a>
</div>
<div class="card-reveal" style="font-size: 15px">
<span class="card-title grey-text text-darken-4"><center>{{event.title}}</center><i class="material-icons right">close</i></span>
<hr>
<center>
<p class="truncate">{{event.description}}</p>
<hr>
<p>Starts {{event.start}}</p>
<iframe width="210" height="190" frameborder="0" style="border:0" src="{{event.address|secureUrl}}" allowfullscreen></iframe>
</center>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`
})
export class AppComponent {
public rows = GROUPS;
}
var EVENTS = [
{
id: 95,
title: "Event Name",
description: "The awesome event description",
thumbnail: "https://ucarecdn.com/58955d6b-bd4c-41f3-8a7b-4ce2bf013b13/IMG_4229.JPG",
access: "public",
code: null,
start: "1 week ago",
end: "6 days ago",
address: "https://www.google.com/maps/embed/v1/place?key=KEY",
host: {
data: {
id: 23,
avatar: "http://www.gravatar.com/avatar/9e557072ab393aa2fca6701eb7b23853?s=45&d=mm"
}
},
category: {
data: {
id: 1,
title: "Wedding",
description: "A marriage ceremony."
}
}
}
];
var chunk_size = 3;
const GROUPS = EVENTS.map(function(e,i){
return i%chunk_size===0 ? EVENTS.slice(i,i+chunk_size) : null;
})
.filter(x=>!!x)
You can use PIPE with DomSanitizationService as shown below;
//our root app component
import {Component, Pipe} from '#angular/core'
import {DomSanitizationService} from '#angular/platform-browser';
#Pipe({name: 'secureUrl'})
export class Url {
constructor(private sanitizer:DomSanitizationService){
this.sanitizer = sanitizer;
}
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url).changingThisBreaksApplicationSecurity;
}
}
#Component({
selector: 'my-app',
pipes: [Url],
template: `
<div *ngFor="let item of myUrls; let i = index">
{{item.url|secureUrl}}
</div>
`,
})
export class AppComponent {
myUrls=[{url:"google.com"},{url:"google1.com"},{url:"google2.com"}];
}