I am using a masonry container and lightbox together to create a gallery page on my site.
<div id="macy-container" style="visibility:none;">
<div *ngFor="let image of _albums; let i=index" [className]="'demo'">
<img [src]="image.src" (click)="open(i)" [className]="'demo-image'" alt=""/>
</div>
</div>
I'm having an issue where if I hard code the images everything works great but as soon as I try to render dynamically the masonry doesn't render. If you try to inspect then the control will render. I've also tried doing a timeout function which will render the control correctly.
I'm realizing that this is basically a race issue. My image data is coming from a service:
getImageData(){
return this.http.get("./assets/eat.json")
.map((res:Response) => res.json().images); //records in this case
}
In the page where I want that data I'm calling the service in my constructor thusly:
import { AppService } from './../core/app.service';
import { EatModule } from './eat.module';
import { Component, OnInit, AfterContentInit } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Lightbox } from 'angular2-lightbox';
#Component({
selector: 'app-eat',
templateUrl: './eat.component.html',
styleUrls: ['./eat.component.scss'],
providers: [ AppService ]
})
export class EatComponent implements OnInit, AfterContentInit {
private _album: Array<string> = [];
public _albums:Array<any> = [];
private myJsonData : any;
constructor(private _lightbox: Lightbox,private http: Http, private appService: AppService) {
this.appService.getImageData().subscribe((data) => {
console.log("JSON data is - ", data);
this.myJsonData = data;
for(let result of this.myJsonData){
const album = {
src : result.src,
caption : result.caption,
thumb : result.thumb
}
this._albums.push(album);
}
});
}
Then in my ngOnInit I load my styles for my masonry:
ngOnInit() {
var masonry = new Macy({
container: '#macy-container',
trueOrder: false,
waitForImages: true,
debug: true,
margin: {
x: 10,
y: 10
}
})
}
There aren't any errors and the page renders but doesn't apply the styles to the masonry container. If you inspect the page then the styles magically appear and the page renders correctly.
Related
Using Angular 2 I've created an application that needs to load an external html, to achieve this I did a simple node api to serve the external html and finally render this external file into my angular 2 application. This is what I want, that works perfectly.
app.component.html
<main>
<h1>Hi, from the container</h1>
<test-component></test-component> <!-- The external html -->
<main>
myExternalFile.html
<main>
<h2>Hi, Im the external file</h2>
</main>
test.component.ts
import { Component, Input, Pipe } from '#angular/core';
import { Http } from '#angular/http';
import { BrowserModule, DomSanitizer } from '#angular/platform-browser';
#Component({
selector: 'test-component',
template: `<div [innerHTML]="myExternalHTML"></div>`
})
export class TestComponent {
myExternalHTML: any = "";
constructor(http: Http, private sanitizer: DomSanitizer ) {
http.get('http://localhost:5000/api/v1/todos') // my basic node app
.subscribe((response: any) => {
const externalHTML=
this.sanitizer.bypassSecurityTrustHtml(response.text());
this.myExternalHTML= externalHTML;
}, (error: any) => {
console.log('Error: ' + error);
})
}
}
So this works, after that I can see the html loaded without any problem. Now I need to add a button with an action that will be processed on the angular2 container.
Like adding a button in the external html (myExternalFile.html)
<main>
<h2>Hi, Im the external file</h2>
<button (click)="hi()">say hi!</button>
</main>
And adding the method (test.component.ts)
import { Component, Input, Pipe } from '#angular/core';
import { Http } from '#angular/http';
import { BrowserModule, DomSanitizer } from '#angular/platform-browser';
#Component({
selector: 'test-component',
template: `<div [innerHTML]="myExternalHTML"></div>`
})
export class TestComponent {
myExternalHTML: any = "";
constructor(http: Http, private sanitizer: DomSanitizer ) {
http.get('http://localhost:5000/api/v1/todos') // my basic node app
.subscribe((response: any) => {
const externalHTML=
this.sanitizer.bypassSecurityTrustHtml(response.text());
this.myExternalHTML= externalHTML;
}, (error: any) => {
console.log('Error: ' + error);
})
}
// New method
hi() {
console.log('we made connection!')
}
}
But, I'm not getting any message on my console. How can I stablish this kind of connection? since everything is already compiled... adding and external file in this ways makes me thing more about this kind of communication.
<main>
<h2>Hi, Im the external file</h2>
<button id="mybtn" (click)="hi()">say hi!</button>
</main>
app.component.ts
import { Component, Input, Pipe } from '#angular/core';
import { Http } from '#angular/http';
import { BrowserModule, DomSanitizer } from '#angular/platform-browser';
#Component({
selector: 'test-component',
template: `<div [innerHTML]="myExternalHTML"></div>`
})
export class TestComponent {
myExternalHTML: any = "";
constructor(http: Http, private sanitizer: DomSanitizer ) {
http.get('http://localhost:5000/api/v1/todos') // my basic node app
.subscribe((response: any) => {
const externalHTML=
this.sanitizer.bypassSecurityTrustHtml(response.text());
this.myExternalHTML= externalHTML;
}, (error: any) => {
console.log('Error: ' + error);
})
}
ngAfterViewInit(){
let el = document.getElementById('mybtn') as HTMLElement;
el.click();
}
// New method
hi() {
console.log('we made connection!')
}
}
I have a component called NewCustomerComponent and I want to load and display it through a modal popup in another page/component when a button is clicked. I have written the relevant bit of code [or so it seems]. But I am getting the following error --
this._childInstance.dialogInit is not a function
at ModalDialogComponent.dialogInit (modal-dialog.component.js:65)
at ModalDialogService.openDialog (modal-dialog.service.js:26)
at OrderNewComponent.newCl (order-new.component.ts:85)
My code is pretty simple too, in the component where I am trying to open the modal popup.
I'll just post the relevant portions --
import { Component, Inject, ViewContainerRef, ComponentRef } from
'#angular/core';
import { Http, Headers } from '#angular/http';
import { Router } from '#angular/router';
import { Observable, Subject } from 'rxjs';
import 'rxjs/add/operator/map';
import { CustomerSearchService } from '../../../shared/services/customer-
search.service';
import { ICustomer, Customer, CustomerD } from
'../../../shared/models/customer';
import { ModalDialogModule, ModalDialogService, IModalDialog } from 'ngx-
modal-dialog';
import { NewCustomerComponent } from
'../../../components/popups/customer/customer-new.component';
#Component({
selector: 'order-new',
templateUrl: './order-new.component.html'
})
export class OrderNewComponent {
public reference: ComponentRef<IModalDialog>;
constructor(private cusService: CustomerSearchService, private http:
Http, private modalService: ModalDialogService, private viewRef:
ViewContainerRef) {
}
ngOnInit(): void {
}
** this is where I am trying to load the newcustomercomponent and open it
in the popup. not working.
newCl() {
this.newC = true;
this.exiC = false;
this.modalService.openDialog(this.viewRef, {
title: 'Add New Customer',
childComponent: NewCustomerComponent
});
}
}
** edits. NewCustomerComponent code added for reference.
import { Component, Input, Output, EventEmitter, OnInit,
ChangeDetectorRef, Directive, ElementRef, Renderer, AfterViewInit }
from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { NgFor } from '#angular/common';
import { Observable } from 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/Rx';
import { PlatformLocation } from '#angular/common';
import { Http } from '#angular/http';
import { ICustomer, Customer } from '../../../shared/models/customer';
import { UserService } from '../../../shared/services/UserService';
import { IModalDialog, IModalDialogOptions, IModalDialogButton } from
'ngx-modal-dialog';
#Component({
selector: 'new-customer',
templateUrl: './customer-new.component.html'
})
export class NewCustomerComponent implements IModalDialog {
model: Customer = new Customer();
errors: any;
submitResponse: any;
actionButtons: IModalDialogButton[];
constructor(private userService: UserService, private http: Http) {
this.actionButtons = [
{ text: 'Close', onAction: () => true }
];
}
ngOnInit() {
}
dialogInit(reference: ComponentRef<IModalDialog>, options:
Partial<IModalDialogOptions<any>>)
{
// no processing needed
}
createCustomer() {
this.userService.createCustomer(this.model)
.take(1)
.subscribe(
(response: any) => {
this.submitResponse = response;
if (response.success) {
console.log('New customer added!');
}
else {
console.log('Unable to add customer!');
}
},
(errors: any) => this.errors = errors
);
return false;
}
cancelClicked() {
}
}
What did I do wrong here? Has it got something to do with the element reference I added in terms of the viewRef? Which portion is erroneous? What about that child component? Does it require to have some specific configuration/markup/component for this to work? I am very new to angular; I am not sure whatever the reason is.
Kindly help me rectify this scenario.
Thanks in advance,
Can you please ensure that the NewCustomerComponent is implementing the IModalDialoginterface. Also, if this is not the case can you please share the code of NewCustomerComponent as well.
edits
Looks like you have not defined the dialogInit method in the NewCustomerComponent and it didn't pop up before as you have not implemented the interface IModalDialog. I would request you to define the dialogInit method in the component class as suggested on the link.
I have a problem with Angular 2 routing. When I click on my link to get the team details, it takes the right route and loads the component specified (TeamComponent). But, immediately "gets back" to the previous component (TeamsComponent), which is the teams list.
This is the structure of my project:
/app
|_shared
|_team
|_team.component.css
|_team.component.html
|_team.component.ts
|_team.model.ts
|_team.service.ts
|_team-list
|_team-list.component.css
|_team-list.component.html
|_team-list.component.ts
|_teams
|_teams.component.css
|_teams.component.html
|_teams.component.ts
|_teams.module.ts
|_teams-routing.module.ts
First, I set the routes on teams-routing.module.ts:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { TeamsComponent } from './teams.component';
import { TeamComponent } from '../shared/team/team.component';
const teamsRoutes: Routes = [
{
path: 'team/:id',
component: TeamComponent
},{
path: 'teams',
component: TeamsComponent
}
];
#NgModule({
imports: [
RouterModule.forChild(teamsRoutes)
]
})
export class TeamsRoutingModule { }
Load the team list from the teamService on teams.component.ts and send it to team-list on teams.component.html:
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/from';
import { TeamService } from '../shared/team/team.service';
import { Team } from '../shared/team/team.model';
#Component({
selector: 'app-teams',
templateUrl: './teams.component.html',
styleUrls: ['./teams.component.css']
})
export class TeamsComponent implements OnInit {
teamList: Team[] = [];
constructor(private teamService: TeamService) { }
ngOnInit() {
this.teamService.getTeams().subscribe(teams => {
Observable.from(teams).subscribe(team => {
this.teamList.push(team);
});
});
}
}
teams.component.html
<section class="teams">
<app-team-list [teams]="teamList"></app-team-list>
</section>
Then, with my teams list, I set the HTML list on team-list.component.html:
<section *ngFor="let team of teams" class="team_list">
<div class="card" style="width: 20rem;">
<img class="card-img-top" src="/assets/logos/{{team.logo}}" alt="Team Logo">
<div class="card-block">
<h4 class="card-title">{{team.name}}</h4>
<p class="card-text">{{team.location}}</p>
<a routerLink="/team/{{team.id}}" class="btn btn-primary">Team Info</a>
</div>
</div>
</section>
Finally, I get the team info from param "id" and the service in team.component.ts:
import { Component, Input, OnInit } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Team } from './team.model';
import { TeamService } from "./team.service";
import 'rxjs/add/operator/switchMap';
#Component({
selector: 'app-team',
templateUrl: './team.component.html',
styleUrls: ['./team.component.css']
})
export class TeamComponent implements OnInit {
team: Team = null;
constructor(private teamService: TeamService,
private activatedRoute: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
let teamId: number = this.activatedRoute.snapshot.params['id'];
console.log("Vamos a buscar el equipo");
this.teamService.getTeamById(teamId).subscribe(team => this.team = team);
}
}
It loads the TeamComponent HTML with the team data, but gets back to /teams direction (and doesn't print the team list). I tried to change the routes names (/detail/:id for example) but still doesn't work. Any suggestions? Thanks in advance.
Ok, got it. Your request will be exuted async, so at the creation-time of your component, team is null. I think you have a binding like this in your TeamComponent:
{{ team.name }}
If team is null, name cannot be accessed and it crashes. To be sure the html will be rendered without errors, use the elvis-operator like this:
{{ team?.name }}
This will only access name if team is not null or undefined
Update: The getTeamById service
getTeamById(id: number): Observable<Team> {
let team: Team = null;
return this.http.get(this.urlTeams+'/'+id)
.map(response => {
let dbTeam: any = response.json();
for(let i in dbTeam) {
team = new Team(dbTeam[i].teamId,dbTeam[i].teamName,dbTeam[i].teamLocation,dbTeam[i].teamFoundation,dbTeam[i].teamDivision,dbTeam[i].teamConference,dbTeam[i].teamStadium,dbTeam[i].teamAttendance,dbTeam[i].teamLogo,dbTeam[i].teamStadiumPhoto);
}
return team;
})
.catch(this.handleError);
}
I am not sure what i am missing from my code but currently i am not presented with any errors when i run it but i am also not seeing the results that i am expecting. I have a json file that i am loading into an array and would like to loop through that array and display parts of its data onto the page.
Here is what i have so far:
Service file
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
#Injectable()
export class AddressDataService{
addressData: Array<any>;
constructor(private http:Http){ }
getAddressData(){
return this.http.get('./api/addressData.json')
.map((res:Response) => res.json());
}
}
JSON File
[{
"type": "home",
"id": 1
}, {
"type": "apartment",
"id": 2
}, {
"type": "homeless",
"id": 3
}]
Component File
import { Http } from '#angular/http';
import { AddressDataService } from './address.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
#Component({
selector: 'my-app',
templateUrl: '....',
styleUrls: ['./styles.css'],
providers: [AddressDataService]
})
constructor(private addressDataService: AddressDataService) {}
addressData = [];
getAddressData() {
this.addressDataService.getAddressData()
.subscribe(data => this.addressData = data);
}
HTML File
<div *ngFor="let addressDetail of addressData">
{{addressDetail.type}}
</div>
Am i doing this the right way?
You need to call your getAddressData for example in your OnInit, I assume you want to fetch the data when navigated to page.
So:
ngOnInit() {
this.getAddressData();
}
When this is handled, you will face another issue. Http-requests don't allow relative paths, so
return this.http.get('./api/addressData.json')
will cause an error, you need to replace the dot in your "url" with the actual complete path for the json file, starting from the top level folder.
In your component file:
.subscribe(
data => {
const helperArray = [];
for (let key in data) {
helperArray.push(data[key]);
}
}
);
Something in your component class needs to call your getAddressData method. Either the constructor, or a better option is to implement OnInit and call it from there.
I'm working on an application using Ionic 2 together with Angular 2. Now I'm trying to the data from an API and display this on a page.
I can log the data and I think it's correct, but for some reason nothing is being displayed on the page itself:
The API where I'm receiving the data from is located here: http://peerligthart.com/grotekerk/v1/api.php/zerken?transform=1
*ngFor on my view
<ion-content padding>
<h1 *ngFor="let z of zerken">
{{ z.naam }}
</h1>
</ion-content>
Controller
import { Component } from '#angular/core';
import { NavController, PopoverController } from 'ionic-angular';
import { PopoverPage } from '../popover/popover';
import { ZerkenProvider } from '../../providers/zerken';
#Component({
selector: 'page-lijst',
templateUrl: 'lijst.html',
providers: [ZerkenProvider]
})
export class LijstPage {
zerken: Array<any>;
constructor(public navCtrl: NavController, public popoverCtrl: PopoverController, public zerkenProvider: ZerkenProvider) {
this.zerkenProvider.getZerken().subscribe(
data => {
console.log(data.zerken);
this.zerken = data.zerken.results;
}
)
}
openPopover(event) {
let popover = this.popoverCtrl.create(PopoverPage);
popover.present({
ev: event
});
}
}
And last, the provider
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class ZerkenProvider {
static get parameters() {
return [[Http]];
}
constructor(public http: Http) {
}
getZerken() {
var url = "http://peerligthart.com/grotekerk/v1/api.php/zerken?transform=1";
var response = this.http.get(url).map(res => res.json());
return response;
}
}
So, what the page is displaying itself:
As you can see.. nothing. I hope someone has a solution, kind regards!
-------------EDIT-------------
I changed this.zerken = data.zerken.results to this.zerken. After doing this it's giving me an error:
Your zerken in your response doesn't seem to have an results object, so
this.zerken = data.zerken.results;
should be:
this.zerken = data.zerken;
Remember to initialize the array in your component:
zerken: Array<any> = [];
so that you won't get an error that zerken is undefined, since view is usually rendered before data has been received. Having it initialized will prevent that.
You need an *ngIf encapsulating the *ngFor since zerken is obtained at a later point of time.
Try:
<ion-content padding>
<div *ngIf="zerken">
<h1 *ngFor="let z of zerken">
{{ z.naam }}
</h1>
</div>
</ion-content>
Also you need to set zerken = data.zerken; as mentioned in the other answer by #AJT_82.