Cannot set property 'webkitTransition' of undefined? - ionic4

Hello everyone I am working on ionic 4 and face problem while implementing parallax in 'webKitTransition'. I find no solution of this problem. So please tell me. Thank You for your time. Error is given below
ParallaxHideHeaderPage.html:7 ERROR TypeError: Cannot set property 'webkitTransition' of undefined
at EmulatedEncapsulationDomRenderer2.push../node_modules/#angular/platform-browser/fesm5/platform-browser.js.DefaultDomRenderer2.setStyle (platform-browser.js:1118)
at BaseAnimationRenderer.push../node_modules/#angular/platform-browser/fesm5/animations.js.BaseAnimationRenderer.setStyle (animations.js:242)
ParallaxHideHeaderPage.html:7 ERROR TypeError: Cannot set property 'webkitTransition' of undefined
at EmulatedEncapsulationDomRenderer2.push../node_modules/#angular/platform-browser/fesm5/platform-browser.js.DefaultDomRenderer2.setStyle (platform-browser.js:1118)
at BaseAnimationRenderer.push../node_modules/#angular/platform-browser/fesm5/animations.js.BaseAnimationRenderer.setStyle (animations.js:242)
import { Directive, AfterViewInit, ElementRef, Renderer, Input } from '#angular/core';
#Directive({
selector: '[appHideHeader]',
host: {
'(ionScroll)': 'onContentScroll($event)'
}
})
export class HideHeaderDirective {
#Input('header') header: HTMLElement;
headerHeight;
scrollContent;
constructor(private element: ElementRef, private renderer: Renderer) {
console.log(this.header);
}
ngOnInit() {
this.headerHeight = this.header.clientHeight;
this.renderer.setElementStyle(this.header, 'webkitTransition', 'top 700ms');
this.scrollContent = this.element.nativeElement.getElementsByClassName("scroll-content")[0];
this.renderer.setElementStyle(this.scrollContent, 'webkitTransition', 'margin-top 700ms');
}
onContentScroll(event) {
if (event.detail.scrollTop >= 56) {
this.renderer.setElementStyle(this.header, 'top', '-56px');
this.renderer.setElementStyle(this.scrollContent, "margin-top", "0px")
}
else{
this.renderer.setElementStyle(this.header, 'top', '0px');
this.renderer.setElementStyle(this.scrollContent, "margin-top", "56px")
}
}
}
<ion-header #head>
<ion-toolbar>
<ion-title>parallaxHideHeader</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding appHideHeader [header]="head">
<div class="main-content">
<h2>Parallax Header</h2>
</div>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</ion-content>

Make sure your accessing the right element along the element tree. Instead of
this.renderer.setElementStyle(this.header, 'webkitTransition', 'top 700ms');
use
this.renderer.setElementStyle(this.header['el'], 'webkitTransition', 'top 700ms');
Same for "this.scrollContent".

Related

Vue3 - print function result into p vs print function to css section inside html tag

let's say I have a very simple setup using data() and a function written in the methods part. With the function I'm returning a random number between 1 and 3, while the data contains an list of blog elements.
When displaying the result from randomNumber directly on the page using <p>{{randomNumber()}}</p> the value (1-3) get's printed. In my case I'm printing all posts from blogs using v-for on the parent div.
When however, trying to alter a css class with said number the number does not get printed. For this particular test I have made .g1, .g2 and .g3 with different style attributes. When inspecting the source code directly in the browser the .blog-thumb class has g{{randomNumber()}} as a second class.
i tried to call randomNumber() within the blogs item but I'm still unable to add the generated class to the css class section.
Thank you for your help or suggestions.
HTML:
<div class="col" v-for="blog in blogs" :key="blog.id">
<div class="blog-thumb g{{randomNumber()}}"> <!-- DOES NOT GET PRINTED -->
{{randomNumber()}} <!-- GETS PRINTED -->
<p class="date">{{ blog.date }}</p>
</div>
<h2>{{blog.title}}</h2>
<p>{{blog.content}}</p>
</div>
Vue:
methods : {
randomNumber : function(){
return Math.floor(Math.random() * 3+1);
}
},
data() {
return{
blogs: [
{
id: '1',
title: 'Amet consectetur adipisicing',
date: 'March 3rd 2022',
content: 'Lorem ipsum...'
},
{...}
]
}
}
after fiddling with it for quite a while today I found this solution:
I changed the function to return a complete classname (in this case, g with a random number between 1 and 3)
randomNumber : function(){
return 'g' + Math.floor(Math.random() * 3+1);
}
in the html part I added the v-bind to the class and passed the function (v-bind:class="randomNumber()")
<div class="col" v-for="blog in blogs" :key="blog.id">
<div class="blog-thumb" v-bind:class="randomNumber()">
<p class="date">{{ blog.date }}</p>
</div>
<h2>{{blog.title}}</h2>
<p>{{blog.content}}</p>
</div>
with this, now every col blog-thumb class got another generated class added to it.

Vue v-for _vm.item is undefined

i'm using Quasar Framework 1.0.5, Vue 2.6, Vue-apollo.
I have a problem with v-for
In the browser console i get a error _vm.item is undefined even though the data is there.
The code works like this that in the data section i initialize my array to an empty array. Then when the user clicks vue-apollo is making a request to the backend and updates the array.
The data section:
data() {
return {
eventsByDay: []
}
},
The vue-apollo update function (where the data is loaded from the API):
I'm using the apollo option.
apollo: {
loadTermine: {
query: TermineByDayQuery,
...
result ({ data, loading, networkStatus }) {
console.info('before:');
console.info(this.eventsByDay);
this.eventsByDay = data.TermineByDayQuery;
console.info('after:');
console.table(this.eventsByDay);
},
The template (in PUG, which generates html):
q-card-section.q-mx-none.row(v-if="eventsByDay.length > 0")
q-item.col.text-left.q-pa-none
q-item-section
.text-grey-7 {{this.selectedDate | formatDate}}
p.text-black.q-mt-lg.text-weight-bold(v-for="item in eventsByDay" :key="item.id") Lorem ipsum dolor
.row
p.col.text-grey-7.q-mt-xs 07:50 Uhr
p.col.text-grey-7.q-mt-xs.text-right Ort {{eventsByDay.length}} {{item.city}}
The problem is the last {{item.city}} . There it says _vm.item is undefined. When i remove this then there is no error. Even {{eventsByDay.length}} shows the correct length of the array - 2.
The elements are there in the Array:
Any idea what i doing wrong?
Solved by removing the leading p in the template:
.text-black.q-mt-lg.text-weight-bold(v-for="item in eventsByDay" :key="item.id") Lorem ipsum dolor
Dont know why this is a problem. PUG?

angular 2 spinner, slider: custom pipe not working

The following is the section of my angular component template that is not working:
<p-spinner id="yzDistance"
[min]="aRenderState.clipping.planes[0].min"
[max]="aRenderState.clipping.planes[0].max"
[step]="inputStep"
[(ngModel)]="yzDistance" (onChange)="moveClip(0)">
</p-spinner>
<input type="range" class="slider" type="range" name="yzDistance"
[min]="aRenderState.clipping.planes[0].min"
[max]="aRenderState.clipping.planes[0].max"
[step]="inputStep"
[ngModel]="yzDistance | decimalsPipe"
(ngModelChange)="yzDistance=$event"
(input)="moveClip(0)">
the spinner is working fine showing values formatted correctly e.g 2.009 4.765 -1.649 etc. (3 decimal places). When I move the slider that also has a step of 0.001 the spinner get updated but displays decimals with thousand separators e.g. 3.987,432 -1.34,092 etc. I have tried to correct the problem with the following custom pipe called decimalsPipe:
#Pipe({name: 'decimalsPipe'})
export class DecimalsPipe implements PipeTransform {
transform(value) {
value.toLocaleString('en-US', {
minimumFractionDigits: 0,
maximumFractionDigits: 3
});
}
}
#Component({
selector: 'myComponent',
templateUrl: './myComponent.html',
styleUrls: ['./myComponent.css']
})
export class myComponent { ...
it still showing the weird decimal formatting and it does not raise errors. Can you help me to sort this out?
Thank you, Dino
u do not return any value in transform , try to return the formatted value in the method transform :
transform(value) {
return value.toLocaleString('en-US', {
minimumFractionDigits: 0,
maximumFractionDigits: 3
});
}
I have accepted Med_Ali_Rachid answer even if it doesn't work as his answer point me in the right direction. The problem is the spinner that is not formatting the value returned by the pipe.
My solution was to hide the input area of the spinner leaving only the up and down arrows buttons visible. Then I have added a paragraph styled as an input to display the correct value.
<p>
{{yzDistance | decimalsPipe}}
</p>
<p-spinner id="yzDistance"
[min]="aRenderState.clipping.planes[0].min"
[max]="aRenderState.clipping.planes[0].max"
[step]="inputStep"
[(ngModel)]="yzDistance" (onChange)="moveClip(0)">
</p-spinner>

Angular 2 http - get data from API

I'm trying to get data in JSON format from this site https://api.chucknorris.io/ (random joke), but i get an error:ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. And "DebugContext_ {view: Object, nodeIndex: 11, nodeDef: Object, elDef: Object, elView: Object}"
This is routing.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class RandomService {
constructor(private http: Http) {
console.log('working');
}
getRandomJokes() {
return this.http.get('https://api.chucknorris.io/jokes/random')
.map(res => res.json());
}
}
This is the component i'm trying to get data into
<div *ngFor="let joke of jokes">
<h3>{{joke.value}}</h3>
</div>
`,
providers: [RandomService]
})
export class PocetnaComponent {
jokes: Joke[];
constructor(private jokesService: RandomService){
this.jokesService.getRandomJokes().subscribe(jokes => {this.jokes = jokes});
}
}
interface Joke{
id: number;
value: string;
}
Since what you are receiving is not an array, but an object, therefore the error you are getting is because an object cannot be iterated. You might want to rethink the naming, since we are dealing with just one object, joke would be a more suitable name. But here, let's use jokes.
So you should do is remove the *ngFor completely and simply display the value with:
{{jokes?.value}}
Nothing else is needed :) Notice the safe navigation operator here, which safeguards null and undefined values in property paths. Be prepared to use this a lot in the asynchronous world ;)
Here is more info about the safe navigation operator, from the official docs.
You are not binding an array to the *ngFor, you have to make sure that jokes is actually an array and not a random joke object.
To solve it if it is an object you can just do this.jokes = [jokes].
The url you mention only provides a single value in an object, so you cannot iterate over it.
Maybe make multiple calls like this:
getRandomJokes(n = 10){
return Promise.all(Array(n).fill(0)
.map(() => this.http.get('https://api.chucknorris.io/jokes/random').toPromise()
.then(res => res.json()));
}
and use with promise
this.jokesService.getRandomJokes().then(jokes => {this.jokes = jokes});
you can check if it is an array and then go for ngFor or convert the jokes to array like let jokes = [jokes];
<div *ngIf = "jokes.length > 0" ; else check>
<div *ngFor="let joke of jokes">
<h3>{{joke.value}}</h3>
</div>
</div>
<ng-template #check>
<p>print the value of the object </p>
</ng-template>
May be jokes isn't an array.
<div *ngIf="Array.isArray(jokes)>
<div *ngFor="let joke of jokes">
<h3>{{joke.value}}</h3>
</div>

Aurelia - bound control's backing property setter called twice

I implemented a custom control which is basically a styled file uploader specifically for images, which allows the preview of images. The problem is that I experience a weird behavior: the setter of the property to which the regular HTML <input type="file"> is bound gets called twice in FF 53, IE 11, Edge 38, but not in Chrome 57. I have no idea why this happens, perhaps some of you have experienced similar behavior and know a solution.
The markup is the following:
<template>
<!-- markup for preview functionality, irrelevant here -->
<input type="file" class="sr-only" id="${id}" aria-describedby="${id}-help" multiple accept="image/*" files.bind="imageGroup" />
<label class="btn btn-default btn-sm" aria-hidden="true" for="${id}" role="button">
<i class="fa fa-plus" aria-hidden="true"></i> Add files
</label>
</template>
The backing TypeScript code:
import { bindable, bindingMode, autoinject } from 'aurelia-framework';
import { DialogService } from 'aurelia-dialog';
import { Confirm } from '../confirm';
#autoinject
export class ImageUploader {
#bindable({ defaultBindingMode: bindingMode.twoWay }) imageArray: Array<File> = null;
#bindable id: string = null;
#bindable maxImageCount: number = 10;
#bindable maxFileSizeKiloBytes: number = 2048;
constructor(private dialogService: DialogService) { }
idChanged(newValue: string) {
if (!newValue) {
throw Error('The id parameter needs a value in order to make the file uploader work.');
}
}
set imageGroup(fileList: FileList) {
console.log('imageGroup');
if (!fileList || !fileList.length) return;
if (!this.imageArray) return;
for (let i = 0; i < fileList.length; ++i) {
let file = fileList.item(i);
if (this.imageArray.length >= this.maxImageCount) {
// TODO: Alert: maximum number of images reached
} else {
if (file && file.type.startsWith('image/')) {
// Size is in bytes. Div by 1024 to get kilobytes.
if (file.size / (1024) > this.maxFileSizeKiloBytes) {
// TODO: Alert: Image file too large.
} else {
this.imageArray.push(file);
}
} else {
// TODO: Alert: unsupported media type.
}
}
}
}
}
As you can see, I use the "hide the default file uploader and style a bound label instead" trick to style the uploader itself - I only say this to point out that I've checked if maybe this is the cause, but it's not, the same behavior can be experienced if I show the default file uploader and use that.
You can also see that I've bound the <input type="file"> to a setter-only property. I've done that because this property is basically just a proxy which populates another array (which is not in the control, this is what is bound to the control) which is necessary because I need to allow the user to upload files in multiple turns so that (s)he can select files from different folders.
The rest of the code is irrelevant, because the console.log line runs twice whenever I select some files, so the error is located somewhere here - I am just unable to figure out exactly what is causing this to happen.
Any help is appreciated.
I confirmed that using setter on that case causes to call your setter two times in FF, aurelia created another setter for every property that needs to observe. However you can achieve same behavior using observable with minimal changes and also provided encapsulation in this case. See those gist.run link. More info here.
UPDATE
For Firefox this is still open as a bug. But a workaround using change.delegate as elefantino and abemeister said works on FF, see gist here.