This question already has answers here:
*ngFor running an infinite loop in angular2
(1 answer)
Angular2 *ngIf="afunctioncall()" results in the function being called 9 times
(1 answer)
Closed 5 years ago.
I am experiencing a very weird behavior of [disabled]. I am fetching a list of firebase docs and showing them using *ngFor.
app.component.ts
export class AppComponent implements OnInit {
postRef;
posts = [];
user;
counter = 1;
constructor( private afs: AngularFirestore ) { }
ngOnInit() {
this.postRef = this.afs.collection('post');
this.posts = this.postRef.valueChanges();
}
editPost(post) {
console.log('Edit-Post : ', post.title);
}
canEdit(post) {
console.log('CanEdit-Post : ', post.title);
console.log('Counter :', this.counter++);
return false;
}
deletePost(post) {
console.log('Delete-Post : ', post.title);
}
}
app.component.html
<div *ngFor="let post of posts | async" class="card" style="width:80%;margin: 50px 40px;">
<h5 class="card-header">{{ post.title }}</h5>
<div class="card-body">
<p>{{ post.content }}</p>
<button class="btn btn-warning is-danger" (click)="deletePost(post)"> Delete Post </button>
<button class="btn btn-primary is-warning" [disabled]="canEdit(post)" (click)="editPost(post)"> Edit Post </button>
</div>
</div>
canEdit() on [disabled] called so many times on page load (around 12 times, I have checked by console 'counter' in canEdit().
canEdit() also called on click of 'Edit Post' and 'Delete Post' button that too 6 times each. And sometimes canEdit() called automatically without any method calling or page load/refresh.
This is really weird behavior for me, anyone please explain the behavior of [disabled] here in detail.
NOTE : This behavior has nothing to do with list of post getting from firebase database collection as I have already checked this with static list of posts. I using angular v^5.0.0
that's because what you write in ngOnInit you are loading posts at first /
and render them using *ngFor
here is the scenario when it starts rendering
he checks for each button if it is disabled at first or not, that why he calls canEdit the same number of posts
and if you try to change the posts array canEdit will called again with the same scenario
Related
I have been trying for a few days that when I use the .sort property the data is eliminated or modified instead of it being reloaded as new lines.
Attach Captures from the code Working
Image1 How work the code when i press the button, this sort to the highest price to lowest but how do you can see in the second image, the code appears up and this not delete the old data
Marked with "X" the data that does not have to show
this fragment is the one that generates the tables dynamically
const mostrarProductos = () => {
$.getJSON(URLJSON, (respuesta) => {
for (let z of respuesta) {
productosv2.push(z);
}
for (let x of productosv2) {
$("#fila").append(`
<tr class="deleteProductos">
<div class="card text-center" style="width: 18rem;" id='btnBorrarCarrito'>
<div class="card-body">
<input type="hidden" id="idProd" value="${x.id}"> </td>
<td class="card-title" id="${x.id}">${x.producto}</h2> </td>
<td class="card-text">$ ${x.precio}</p></td>
<div class="btn-group" role="group" aria-label="Basic mixed styles example">
<td><button type="button" class="btn btn-success" onclick="agregarCarrito(${x.id})">Agregar</button></td>
</div>
</div>
</div>
</tr>
`);
}
$("#fila").fadeIn("5000");
});
};
And this function is what orders them
function respuestaClickExpensive() {
$("#fila").html('');
let productosordenados = productosv2.sort((a, b) => {
if (a.precio > b.precio) {
return -1;
}
if (a.precio < b.precio) {
return 1;
}
return 0;
});
return productosordenados;
}
The one that orders them from smallest to largest is the same only that different signs and names.
As you can see I tried to use a ".html ("")" since previously in another cart attempt it used .innerHtml (Which does not work in this case either, Also the code of the cart is totally different from that moment that it worked for me
)
I tried the following:
$ ("#fila"). empty ();
Make another function to clean with .empty
Use Native JavaScript to generate the code.
$ ("#fila"). remove (); this removes all the content for me but does not regenerate it.
Change the HTML tag "Row" to a previous div which, since the div was not generated again, did not generate it again.
$ ("#fila tr"). remove ();
And some more things that I don't remember right now.
If you can guide me on what I did wrong or any suggestions to fix it, I appreciate it.
If I had to follow a template about posting on StackOverFlow or having chosen or named in a different way, I appreciate your comment since it is my first post
Project notes of possible relevance: The complete code outside of html and css is made with Native JavaScript, Jquery, Ajax, SASS and BootStrap.
This question already has an answer here:
Why does javascript object show different values in console in Chrome, Firefox, Safari? [duplicate]
(1 answer)
Closed 3 years ago.
Vuejs beginner here, I have this Reservation System that checks out availability with CheckIn, CheckOut, and RoomCapacity using a datepicker and two number inputs (one for Adult and one for kids) and using axios.get to get the values. The CheckIn and CheckOut works fine, but the RoomCapacity stays none in the query string params but when console logging, it shows the value.
Here's The console.log and
the query string params
Here's the Vue code:
<b-tab title="Search Rooms" :disabled="step !== 0">
<div class="date">
<p>Pick a date:</p>
<!-- <date-picker v-model="time1" valueType="format" range ></date-picker> -->
<HotelDatePicker
format="DD/MM/YYYY"
#check-in-changed="updateCheckIn($event),searchCheckIn($event)"
#check-out-changed="updateCheckOut($event), searchCheckOut($event)"
></HotelDatePicker>
</div>
<div class="guestCount">
<p>Number of adults:</p>
<InputNumber :max="14" :min="1" v-model="bookForm.AdultCount" size="large"></InputNumber>
<br />
<p>Number of kids:</p>
<InputNumber :max="10" :min="0" v-model="bookForm.KidCount" size="large"></InputNumber>
<br />
</div>
<br/>
<b-button
#click="step = 1; searchRooms(); check(); totalGuest();"
variant="primary"
>Check Available Rooms</b-button>
</b-tab>
The data:
searchForm:{
CheckInDate:'',
CheckOutDate:'',
RoomCapacity:'',
},
The method:
searchRooms(){
axios.get("http://localhost:3000/searchRooms",{
params:{
CheckInDate: this.searchForm.CheckInDate,
CheckOutDate: this.searchForm.CheckOutDate,
RoomCapacity: this.searchForm.RoomCapacity,
}
})
.then((res)=>{
if(res.data[0]){
// no problem
if(res.data[1].length){
//rows retrieved
this.roomList=res.data[1]
this.notice=""
this.err_msg=""
}else{
//no matching row
this.notice="No rooms found"
this.roomList=[]
this.err_msg=""
}
}else{
this.err_msg = res.data[1]
this.roomList=[]
this.notice=""
}
})
.catch((err)=>{
this.err_msgP="AJAX error"
this.PalacioRooms=[]
this.noticeP=""
})
},
totalGuest(){
let totalGuest = this.bookForm.KidCount + this.bookForm.AdultCount;
this.searchForm.RoomCapacity = totalGuest.toString();
},
check(){
console.log(this.searchForm)
},
I tried making the RoomCapacity to 0 but same problem, it just stays zero.
I don't have enough information about your code to tell this for sure but in most cases if console.log shows another value than Vue itself seems to know it is because of a value change not recognized by Vue's getters and setters in the current JS event cycle.
This can happen if you use own class instance method outside of the Vue context to change an instance's properties. It's better explained in the docs: https://v2.vuejs.org/v2/guide/reactivity.html
To fix this you should be fine using the $set command to trigger Vue's reactivity manually.
I've got a function that checks the value of an observable and based on that value performs some logic to change the value of a variable that I've defined in a service. Everything is working as it should except that the changed value is not rendering (updating) in the web component through string interpolation when it gets changed. It is being changed correctly in the service (when I console.log it is coming back correctly) but just not getting it to update the component for some reason. I've read a lot about ngZone, ChangeDetectorRef etc. and have implemented those strategies on other areas where I've had update issues in the past, but for some reason they are not working here. Code below, any guidance would be appreciated as I've banged my head against this one for a while.
//From the component where I'm performing the checks on the observable. The component where I'm doing the string interpolation on the data service value is a different component
ngOnInit(){
this.myObservable$ = this.scanitservice.decodedString$.subscribe(data => {
if (
data ==
this.adventuredata.exhibit[this.adventuredata.adventure.currentAmount]
.target
) {
this.adventuredata.sharedVariables.guideText =
'You found the right clue! Great job! Answer the question correctly to claim your prize.';
console.log(this.adventuredata.sharedVariables.guideText);
this.showQuiz = true;
this.changeDetector.detectChanges();
console.log('Evaluated as matched');
}
});
}
//From the data service
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class AdventuredataService {
constructor() {}
sharedVariables = {
guideText: '',
quizText: ''
};
}
<div class="card-body float-right m-0 p-0">
<img
src="{{ this.adventuredata.adventure.guideImage }}"
alt=""
class="card-img-top w-25 float-left"
/>
<span class="card-text p-0">
{{ this.adventuredata.sharedVariables.guideText }}
</span>
</div>
My component's html is this:
<div id="summary">
<div *ngFor="let question of thisSurvey">
<div>
<span class="badge">#{{question.questionNumber}}</span>
<span>{{question.questionText}}</span>
</div>
<p>Your answer: {{question.questionAnswer}}</p>
</div>
</div>
<br/>
<button class="btn btn-danger yes-no-btn" routerLink="/survey">Go Back</button>
<button class="btn btn-primary" [routerLink]="submitSurvey()" routerLinkActive="active">Finish</button> <!-- Issue here -->
When the page loads, submitSurvey is invoked immediately, and is then constantly invoked. This is submitSurvey:
// Send the answers back to the api for processing
submitSurvey() {
// Make sure everything is answered
const allOKClientSide: boolean = this.surveyService.checkEntireForm(this.thisSurvey);
if (allOKClientSide) {
if (this.surveyService.checkFormOnline(this.thisSurvey).subscribe()) {
return '/placeOne';
}
}
return '/placeTwo';
}
The method begins to hit the service immediately and continues until I kill the server. How do I keep the function from being invoked until the button is clicked? I'm new to Angular and am probably just making a rookie mistake, if so you may point that out as well. Thanks in advance.
[routerLink] is an Input, note the []. So Angular will resolve that immediately and every change detection cycle, to satisfy the template. You want to use (click) which is an Output, note the () and will only call when the button is clicked. Then instead of returning the url on the submitSurvey() function call router.navigate() (inject the router first.)
html
<button class="btn btn-primary" (click)="submitSurvey()" routerLinkActive="active">Finish</button>
ts
constructor(private router: Router) { }
public submitSurvey(): void {
// Make sure everything is answered
const allOKClientSide: boolean = this.surveyService.checkEntireForm(this.thisSurvey);
if (allOKClientSide) {
if (this.surveyService.checkFormOnline(this.thisSurvey).subscribe()) {
this.router.navigateByUrl('/placeOne');
return;
}
}
this.router.navigateByUrl('/placeTwo');
}
You want your method to be called when the button is clicked. You can do this by using (clicK):
Instead of
[routerLink]="submitSurvey()"
do
(click)="submitSurvey()"
Then you use the router in your class to do the navigation:
constructor(private router: Router) {}
submitSurvey() {
// ...
this.router.navigate(['/placeOne']);
}
I've been following a course on LinkedIn Learning but clicking on a list and having the values populate a form are not working for me. I'm new to Angular (and development) so apologies if this is silly, or I don't describe it correctly.
I have 2 components and an API service file pulling the data from an ASP.Net Core API:
List-codes
Add-code
Api
list-codes.component.html
<div class="card-body">
<p class="card-text">select a code from the list below.</p>
<ul class="list-group" *ngFor="let code of codes">
{{code.codeName}}
</ul>
</div>
list-codes.component.ts
ngOnInit() {
this.api.getCodes().subscribe(res => {
this.codes = res
})
}
add-code.component.html
<form>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="">:)</span>
</div>
<input type="text" class="form-control" [(ngModel)]="code.codename" name="codename" placeholder="code name">
<input type="text" class="form-control" [(ngModel)]="code.description" name="description" placeholder="description">
</div>
<button (click)="post(code)" class="btn btn-primary">Submit</button>
</form>
add-code.component.ts
export class AddCodeComponent {
code = {}
constructor(private api: ApiService) {}
ngOnit() {
this.api.codeSelected.subscribe(code => this.code = code)
}
post(code) {
this.api.postCode(code)
}
}
api.service.ts
export class ApiService {
private selectedCode = new Subject<any>(); // holds reference to clicked item in list
codeSelected= this.selectedCode.asObservable(); // subscribe
constructor(private http: HttpClient) {}
getCodes() {
return this.http.get('http://localhost:58561/api/codes');
}
postCode(code) {
this.http.post('http://localhost:58561/api/codes', code).subscribe(res => {
console.log(res)
})
}
selectCode(code) {
this.selectedCode.next(code)
}
}
Listing the codes works fine.
The issue just seems to be clicking and having the code in the list populate the values in the add-code form (it works in the video tutorial) but it doesn't work for me. I'm assuming I've missed something obvious?
I did a bit of reading and everyone seems to handle Subject Observables slightly different and I"m obviously just missing the point!
For brevity, I've provided the snippets I think are relevant. If I've overlooked something important to include please let me know.
Any help welcomed!
Cheers,
Adam
In your list-codes.component.ts you only subscribe to the observable returned by your api.service.getCodes() once because an Observable is Cold by default and thus when it completes you automatically unsubscribe.
In order for your form to keep updating you need to implement something that will keep calling your service.getCodes().subscribe(blah) to fetch new data.