I have an ion-card list of elements in a page and I want to navigate to a specific position when entering the view, the page renders properly and I can see in the generated code that div with specific id is indeed on the view but trying to get the element by id is returning null.
Here is the code for the view where I build the cards:
<ion-content class="cards-bg">
<ion-card *ngFor="let meal of meals">
<ion-card-header>
{{meal.date | date: 'dd/MM/yyyy HH:mm'}}
</ion-card-header>
<div id="{{meal.id}}">
<img src="{{serverUrl + '/' + meal.picture}}">
</div>
<ion-card-content>
<ion-card-title>
{{meal.title}}
</ion-card-title>
<p>{{meal.description}}</p>
</ion-card-content>
</ion-card>
<ion-row no-padding></ion-row>
</ion-content>
And this is the code that tries to get the reference to the element so I can navigate to it:
public index: string;
constructor(public navCtrl: NavController, navParams: NavParams, public mealService: MealService) {
this.index = navParams.get('index');
}
ionViewDidEnter() {
this.mealService.getMeals().then((result) => {
this.meals = result;
let yOffset = document.getElementById(this.index).offsetTop;
this.content.scrollTo(0, yOffset, 1000);
}).catch((error) => {
console.log(error);
});
As I mentioned the page with cards render, I can even see the generated code contains the specific div with id but the call:
document.getElementById(this.index)
returns null, so I get the following error in logs:
chromium: [INFO:CONSOLE(57687)] "TypeError: Cannot read property 'offsetTop' of null", source: file:///android_asset/www/build/main.js (57687)
Use Angular`s ElementRef
Inject it in constructor:
constructor(private elRef:ElementRef){}
For getting the element,
let el = this.elRef.nativeElement;//get underlying native element.
let yOffset = el.getElementById(this.index).offsetTop;
Or you could also use ViewChildren:
Set an id for the div:
<div #divElement id="{{meal.id}}">
<img src="{{serverUrl + '/' + meal.picture}}">
</div>
Set the decorator on a class variable:
#ViewChildren('divElement')
divs:any;
For accessing elements,
let yOffset = this.divs[this.index].nativeElement.offsetTop
Related
I'm very new in software project and currently working on final year project, mobile apps using ionic 3 framework. I have drag and drop function, first bucket with list of items and second bucket is empty. When I want to drag the items from 1st bucket to the 2nd bucket, I want to calculate the price for each entry at the second bucket but I really don't have idea to do it. Can someone help me with the codes :(
this is my calculate.ts
q1 = [];
q2 = [];
details: any = [];
totalPrice: number;
constructor(public navCtrl: NavController, private postPvdr: PostProvider, public navParams: NavParams, public dragulaService: DragulaService, public AlertController:AlertController) {
dragulaService.drop().subscribe((value) => {
console.log(value)
});
const bag: any = this.dragulaService.find('bag');
if (bag !== undefined ) this.dragulaService.destroy('bag');
this.dragulaService.createGroup('bag', {
revertOnSpill: true,
});
}
ionViewDidLoad() {
this.details = [];
this.getlist();
this.getTotalPrice()
}
getlist(){
let body = {
aksi: 'get_user'
};
this.postPvdr.postData(body, 'aksi_user.php').subscribe(data => {
for(let detail of data.result){
this.details.push(detail);
console.log(data);
}
});
}
getTotalPrice(){
let totalPrice = 0;
let body = {
aksi: 'get_user'
};
this.postPvdr.postData(body, 'aksi_user.php').subscribe(data => {
for(let detail of data.result){
totalPrice += Number.parseFloat(detail.dest_budget);
}
});
console.log(totalPrice);
return totalPrice;
}
these lines of codes seem weird because i just do try n error
this is my calculate.html
<ion-content padding>
<ion-row>
<ion-col width-50 class="left">
<div class="header">First Bucket</div>
<ion-list [dragula]='"bag"' [(dragulaModel)]="details">
<button ion-item *ngFor="let detail of details">
{{detail.dest_name}}
<p>{{ detail.dest_budget}}</p>
</button>
</ion-list>
</ion-col>
<ion-col width-50 class="right">
<div class="header">Second Bucket</div>
<ion-list [dragula]='"bag"' [(dragulaModel)]="q2">
<div ion-item *ngFor="let detail of q2">
{{detail.dest_name}}
<p>{{ detail.dest_budget }}</p>
</div>
</ion-list>
</ion-col>
</ion-row>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-title>Total Price:</ion-title>
</ion-toolbar>
</ion-footer>
the total price should be showing at the footer
here is my interface looks like
hope someone can help :)
call function here
dragulaService.drop().subscribe((value) => {
this.getTotalPrice();
});
modify the function
getTotalPrice(){
this.totalPrice = 0;
let body = {
aksi: 'get_user'
};
this.postPvdr.postData(body, 'aksi_user.php').subscribe(data => {
for(let detail of data.result){
this.totalPrice += Number.parseFloat(detail.dest_budget);
}
});
}
and bind model
<ion-footer>
<ion-toolbar>
<ion-title>Total Price:{{totalPrice}}</ion-title>
</ion-toolbar>
</ion-footer>
i am creating an Listing ionic application where i am displaying feeds from an API in the home page. It also has some filter options which is an actionsheet with options such as near by, populer and so on. What i want to do is when user click one of the filter for example populer, i want to do display the new feeds on the same page. How can i do so ??
My code base is as below
home.ts
constructor(....){
this.getFeeds();
}
//make api call to get the feeds
getFeeds(){
const data = localStorage.getItem('userToken');
this.userPostData.api_token= data;
this.authService.postData(this.userPostData,'feeds').then((result)=>{
this.responseData = result;
})
}
//Feeds by location
//Actionsheet
filters() {
let actionSheet = this.actionSheetCtrl.create({
title: 'Sort Events by',
buttons: [
{
text: 'Location',
icon:'pin',
handler: () => {
//Make api call to feeds based on location
}
},
{
text: 'Popularity',
icon:'people',
handler: () => {
//Make api call to feeds based on location
}
}
]
});
actionSheet.present();
}
And my home.html is
<ion-card *ngFor="let item of responseData?.feed" tappable (click)="viewDetail(item.id)">
<div class="event-image-holder search-list">
<img src="http://localhost:8000/{{item.photo_url}}"/>
<div class="event-attendee-count">
<ion-icon name="people"></ion-icon> {{item.attendees.length}} are going
</div>
</div>
<ion-card-content>
<div class="event-info">
<div class="event-time">
<!-- 04 Feb -->
{{item.gmt_date_set | date:'dd MMM'}}
</div>
<div class="event-descp">
<h2>{{item.title}}</h2>
<p>
{{item.club.name}}
</p>
</div>
</div>
</ion-card-content>
</ion-card>
After some research here and there tutorials from youtube and udemy, i found that when ever you change the data of the variable it automatically change on the view page.
So in my case if i override the data of this.responseData it will automatically updated on the view page with out much doing.
i am making image upload using ionic 3 app and FileReader , after the image is uploaded i get this as image url
data:image/jpeg;base64,/4AAQSkZJRgABAQ...9oADAMBAAIRAxEAPwD/AD/6AP/Z
something like this , then i store it as is into my database
i noticed that if i open the app at another device the image will still be loaded and show in the view . so i wounder where does this image go after i upload it? where is it saved in my app ? i tried to look into my app folders couldn't find the img
thanks,
Here is the code i am using
<ion-header>
<ion-navbar>
<ion-title>{{ 'ITEM_CREATE_TITLE' | translate }}</ion-title>
<ion-buttons start>
<button ion-button (click)="cancel()">
<span color="primary" showWhen="ios">
{{ 'CANCEL_BUTTON' | translate }}
</span>
<ion-icon name="md-close" showWhen="android,windows"></ion-icon>
</button>
</ion-buttons>
<ion-buttons end>
<button ion-button (click)="done()" [disabled]="!isReadyToSave" strong>
<span color="primary" showWhen="ios">
{{ 'DONE_BUTTON' | translate }}
</span>
<ion-icon name="md-checkmark" showWhen="core,android,windows"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
Ts file:
export class ItemCreatePage {
#ViewChild('fileInput') fileInput;
isReadyToSave: boolean;
item: any;
form: FormGroup;
constructor(public navCtrl: NavController, public viewCtrl: ViewController, formBuilder: FormBuilder) {
this.form = formBuilder.group({
profilePic: [''],
name: ['', Validators.required],
about: ['']
});
// Watch the form for changes, and
this.form.valueChanges.subscribe((v) => {
this.isReadyToSave = this.form.valid;
});
}
ionViewDidLoad() {
}
getPicture() {
this.fileInput.nativeElement.click();
}
processWebImage(event) {
let reader = new FileReader();
reader.onload = (readerEvent) => {
let imageData = (readerEvent.target as any).result;
this.form.patchValue({ 'profilePic': imageData });
};
reader.readAsDataURL(event.target.files[0]);
}
getProfileImageStyle() {
return 'url(' + this.form.controls['profilePic'].value + ')'
}
/**
* The user cancelled, so we dismiss without sending data back.
*/
cancel() {
this.viewCtrl.dismiss();
}
/**
* The user is done and wants to create the item, so return it
* back to the presenter.
*/
done() {
if (!this.form.valid) { return; }
this.viewCtrl.dismiss(this.form.value);
}
}
I have some troubles with setting range sliders inside ion-slides components.
Indeed, when I'm trying to swipe values of range, ionic detects I'm trying to swipe to another slide.
So I've two questions :
Is there a simple way to implement a range inside a ion-slide content with possibility to set data with range sliders without swiping to another slide and at the opposite, possibility to swipe to another slide without impacting range values.
If there isn't any simple way to do this, I've tried to changing direction of swipe to go to another slide, and according to the documentation I've tried it but I've compile error :
SyntaxError: /my/path/diagnostic.js: Unexpected token (8:18) while parsing file: /my/path/diagnostic.js so the error is targetting this line : diagnosticSlides = {
Here my code :
diagnostic.js
import {Page, NavController, NavParams, Slides} from 'ionic-angular';
#Page({
templateUrl: 'build/pages/diagnostic/diagnostic.html'
})
export class DiagnosticPage {
// Code for changing swiping direction -- not working
diagnosticSlides = {
initialSlide: 1,
loop: false,
direction: 'vertical'
};
static get parameters() {
return [[NavController], [NavParams]];
}
constructor(nav, navParams) {
this.nav = nav;
}
}
diagnostic.html
<ion-slides [options]="diagnosticSlides" pager>
<ion-slide style="background-color: blue">
<div class="item range">
<i class="icon ion-volume-low"></i>
<input type="range" name="volume">
<i class="icon ion-volume-high"></i>
</div>
</ion-slide>
<ion-slide style="background-color: red">
<h2>Other slide</h2>
</ion-slide>
</ion-slides>
Could you help me please ?
Thanks by advance,
From Ionic documentation available range component
So you can use ionFocus and ionBlur of this component and use lockSwipes(true) method between these two events.
public swipe: IonSlides;
#ViewChild(IonRange) range: IonRange;
this.range.ionFocus.subscribe(() => {
this.swipe.lockSwipes(true);
});
this.range.ionBlur.subscribe(() => {
this.swipe.lockSwipes(false);
});
This question already has an answer here:
Error if don't check if {{object.field}} exists
(1 answer)
Closed 6 years ago.
I have a problem, I am working with Ionic 2 and angular 2.
I have to show some datas in a view but I get these datas from an API in the same page so when I try to show them in the view, they are undefined yet. How can I wait to load the view after getting these datas?
I have tried onPageWillEnter but it does not work.
Thank you in advance.
You can wrap your template with *ngIf
template: `
<div *ngIf="data">
... <!-- content -->
</div>`
When data is set, the content will be shown.
You can also use the safe-navigation or Elvis operator to avoid error messages
template: `<div>{{data?.someProp}}</div>`
to avoid error messages when data is null
provider allow you get data from server
generate: ionic generate provider MyProvider --ts
#Injectable()
export class MenuProvider {
data: any = null;
constructor(public http: Http) { }
load() {
if (this.data) {
// already loaded data
return Promise.resolve(this.data);
}
// don't have the data yet
return new Promise(resolve => {
// We're using Angular Http provider to request the data,
// then on the response it'll map the JSON data to a parsed JS object.
// Next we process the data and resolve the promise with the new data.
this.http.get('asset/menu.json')
.map(res => res.json())
.subscribe(data => {
// we've got back the raw data, now generate the core schedule data
// and save the data for later reference
this.data = data;
resolve(this.data);
});
});
}
}
menu.ts
import {MenuProvider} from "../../providers/menu-provider/menu-provider";
import {Component, OnInit} from '#angular/core';
import {IONIC_DIRECTIVES, NavController, Modal} from 'ionic-angular';
import {AccountHistoryPage} from "../../pages/account-history/account-history";
/*
Generated class for the MenuComponent component.
See https://angular.io/docs/ts/latest/api/core/ComponentMetadata-class.html
for more info on Angular 2 Components.
*/
#Component({
selector: 'menu-component',
templateUrl: 'build/components/menu-component/menu-component.html',
directives: IONIC_DIRECTIVES,
providers: [MenuProvider]
})
export class MenuComponent {
// menu object
jsonMenu: any;
constructor(public nav: NavController, menuProvider: MenuProvider) {
// TODO: show progress
menuProvider.load().then(data => {
// TODO: turn off menu load json progress
// data after proccessed.
this.jsonMenu = data;
console.log(this.jsonMenu);
}, err => console.log(err));
}
itemClick(moduleNumber: number) {
console.log(moduleNumber);
let page: any = null;
if (moduleNumber == 210102) {
page = Modal.create(AccountSourcePage);
}
if (moduleNumber == 210103) {
page = Modal.create(AccountBeneficiatyPage);
}
if (moduleNumber == 210101) {
page = Modal.create(AccountHistoryPage);
}
this.nav.present(page);
}
}
after that use temple with ngFor, ngIf.... to display
<ion-item *ngFor="let menu of jsonMenu">
<!-- title -->
<div class="khungtieude">
<span class="tieudechinh">{{menu.title}}</span>
<span class="gachgiua"></span>
</div>
<!-- arrows -->
<div class="arrow-container" [hidden]="!(menu.contains.length > 1)">
<ion-icon class="arrow-back" name="ios-arrow-back"></ion-icon>
<ion-icon class="arrow-forw" name="ios-arrow-forward"></ion-icon>
</div>
<!-- slide -->
<!-- using template instead of fix code, i will add later -->
<ion-slides loop>
<!-- page 1 of side -->
<!-- i need loop in total/3 + (total%3==0? 0 : 1) -->
<ion-slide *ngFor="let temp of menu.contains">
<ion-row style="padding-top: 10px;">
<ion-col width-33 center *ngFor="let menuItem of temp.page" (click)="itemClick(menuItem.moduleId)">
<span class="icon-cknb main-menu-ic"></span>
<br/>
<div class="main-menu-text">
{{menuItem.displayName}}
</div>
</ion-col>
</ion-row>
</ion-slide>
</ion-slides>
</ion-item>