Welcome, I have Angular application which should look and work like messenger writing all messaages to MySQL.
The problem is that it looks like this:
But should look like this:
component.html fragment:
<div *ngFor="let m of messages" [style.background-color]="m.to===conversationPartnerId ? 'lightgrey' : 'blueviolet'"
[style.margin-left]="m.to!=conversationPartnerId ? '5%' : '15%'"
[style.margin-right]="m.to===conversationPartnerId ? '5%' : '15%'"
style="width: 80%; height: auto; float: left; margin-top: 5%">
<h3 style="color: white">{{m.text}}</h3>
</div>
component.ts fragment:
export class BrowseComponent implements OnInit {
userKey = null;
profileToDecide: Profiles;
matches: Profiles[];
currentImage: any;
background: any;
decisionResponse: any;
conversationPartnerId: number;
conversationPartnerName: string;
messages: Messages[];
LINES OF OTHER METHODS
...
...
...
getMessages(id: number, name: string): void {
this.setConversationPartnerIdAndName(id, name);
let registerObject: object;
registerObject = {
"key": this.userKey,
"target": this.conversationPartnerId,
};
this.restService.getMessages(registerObject).subscribe(messages => {
this.messages = messages;
})
}
setConversationPartnerIdAndName(id: number, name: string): void { // Set key and name used in html
this.conversationPartnerId = id; // ngStyle formatting
this.conversationPartnerName = name;
}
JSON from API:
I thought this just set the wrong key, to should be to_id, this is my demo, you can follow this.
stackblitz
Related
I'm working on a personal project using Vue3, Nuxt3 and Element Plus. I'm a beginner with JS/TS and Vue3 and I'm having a problem with the Element Plus TreeSelect Component. I am trying to have the TreeSelect Components selected value be an object but it's always the label field of the object that is selected. Here is my components code.
<template>
<div>
<ClientOnly>
<el-select v-model="selectedEntityDefinitionRef">
<el-option v-for="entityDefinition in scheme.schemeDefinition.entityDefinitions"
:key="entityDefinition.label" :label="entityDefinition.label" :value="entityDefinition">
</el-option>
</el-select>
<el-tree-select check-strictly :render-after-expand="false" show-checkbox check-on-click-node
value-key="label" :data="schemeEntitiesRef" v-model="selectedParentEntityRef"/>
</ClientOnly>
<el-button style="margin-top: 12px" #click="printValues">Add</el-button>
</div>
</template>
<script lang="ts" setup>
import { ElTreeSelect, ElSelect, ElOption, ElButton } from 'element-plus';
import { ref, reactive } from 'vue';
class SchemeDefinition {
label: string
entityDefinitions: Array<EntityDefinition> = new Array<EntityDefinition>()
constructor(label: string) {
this.label = label
}
}
class EntityDefinition {
label: string
constructor(label: string) {
this.label = label
}
}
class Scheme {
schemeDefinition: SchemeDefinition
entities: Array<Entity> = new Array<Entity>()
}
class Entity {
label: string
parent: Entity
children: Array<Entity> = new Array<Entity>()
constructor(label: string) {
this.label = label;
}
}
const schemeDefinition: SchemeDefinition = new SchemeDefinition('Scheme Definition');
const fondsEntityDefinition: EntityDefinition = new EntityDefinition('Entity Definition')
schemeDefinition.entityDefinitions.push(fondsEntityDefinition)
const scheme: Scheme = new Scheme()
scheme.schemeDefinition = schemeDefinition
scheme.entities.push(new Entity('Entity'))
const selectedEntityDefinitionRef = ref<EntityDefinition>()
const selectedParentEntityRef = ref<Entity>()
const schemeEntitiesRef = reactive(scheme.entities)
const printValues = () => {
console.log(selectedEntityDefinitionRef.value)
console.log(selectedParentEntityRef.value)
}
</script>
My question is if I am doing something fundamentally wrong here or is my issue a limitation of the component itself? As a newbie any advice or guidance would be greatly appreciated. Thanks
I have a console on the screen that I log things to. The component looks like this.
export class AppComponent { logs: string[]; ... }
<div *ngFor="let log of logs" class="log-type-a">{{log}}</div>
I'd like to set a class on each of the DIVs dynamically. At the moment, each of those is log-type-a but I'd prefer it to be log-type-b when the string contains a certain value (e.g. it starts with "b", so that the class would be log-type-first_char_of_log.
I'm not sure what to google for to being with. I've tried horsing around with ngClass but failed due to ignorance and uncertainty on how.
NgFor can have an index, like this one: *ngFor="let item of items; index as i;"
You could use that index in order to set different classes for your items, like class="log-type-{{ i }}".
https://angular.io/api/common/NgForOf
You can use expresion in ngClass like this:
export class AppComponent { logs: string[]; ... }
<div *ngFor="let log of logs" [ngClass]="'log-type-' + log">{{log}}</div>
If your logs array has lets say: red and blue
the class output should be:
log-type-red
log-type-blue
OR
you can use functions like this and make decisions depending on the log value:
<div *ngFor="let log of logs" [ngClass]="'class-test-' + ngClassConvert (log)">
My log value: {{ log }}
Converted in cssClass: {{ ngClassConvert (log)}}
</div>
and the component:
export class AppComponent implements OnInit {
name = 'Angular';
logs: string[];
ngClassConvert(value):string{
let returnValue = '';
switch (value){
case 'a': {
returnValue = 'Apple';
break;
}
case 'b': {
returnValue = 'Banana';
break;
}
case 'c': {
returnValue = 'Cherry';
break;
}
case 'd': {
returnValue = 'dddd';
break;
}
default: {
returnValue = 'default';
break;
}
}
return returnValue;
}
ngOnInit(): void {
this.logs = ['a', 'b', 'c', 'd'];
}
}
Also and Demo
Based on the answer of SehaxX: You could parse the list of logs using a setter. This will save you function calls in the template.
private _logs: string[];
public parsedLogs: any[];
set logs(value: string[]) {
this._logs = value;
this.parsedLogs = this.parseLogs(value);
}
private parseLogs(logs: string[]): any[] {
let parsed = [];
for (let i = 0; i < logs.length; i++){
parsed.push({
value: logs[i],
style: this.ngClassConvert(logs[i])
});
}
return parsed;
}
Demo
I'm working with Angular 6 and Firebase and what I need is to get all items from the firebase and then display only one at a time till next button click
/*this is the .ts file*/
constructor( public af: AngularFire, public db: AngularFireDatabase) {
this.items = db.list('items').valueChanges();
db.list('/sentences').valueChanges().subscribe(sentences => {
this.sentences = sentences;
console.log(this.sentences);
});
}
<!--this in the html-->
<div>
<ul class="sent">
<li *ngFor="let sentence of sentences"
[class.selected]="sentence === selectedsentence"
(click)="onSelect(sentence)">{{sentence}}
<!-- this is displaying all the items in the firebase; i need only one at a time-->
</li>
</ul>
</div>
//in the ts file
constructor( public db: AngularFireDatabase) {
this.items = db.list('items').valueChanges();
db.list('/sentences').valueChanges().subscribe(sentences => {
this.sentences = sentences;
console.log(this.sentences);
this.labels = this.sentences; //in this.labels we have all the elements *declaration : labels=[]
console.log(this.labels);
});
onSkip($i) {
if (this.i > 13) { //if there are 13 elements in the database
this.i = 0;
}
this.i = this.i + 1;
console.log(this.i);
}
// in the html code
{{labels[i]}}
<button class="centered" (click)="onSkip(i)" > SKIP <a routerLink="skip">
I'm having some trouble displaying my data in the browser. To explain my problem I'm using some dummy code. I have some nested objects that are causing my problem. Here I'll display one nested object to showcase my problem.
First of all, I only make http calls for the Car-object. So saveCar acts like updating the car as well, depending on what the user does in the app. All the methods in the service works as they should.
So my service looks something like this:
#Injectable()
export class Service {
constructor(private http: Http) { }
saveCar(car: Car) {
return this.http.post ....
}
getCars(){
return this.http.get...
}
getById(id: string) {
return this.http.get...
}
}
Then I have a Car-class, where the nested object "Brand" comes in to play, Brand then has it's own class, but I'll leave it out.
export class Car {
private brands: Array<Brand>;
constructor(public id: string, public name: string) {
this.brands = new Array<Brand>();
}
public getBrands(): Array<Brand> {
return this.brands;
}
public addBrand(value: Brand): void {
this.brands.push(value);
}
//some other methods.
}
Then I have a list-component that lists all cars, this works as it should!
#Component({
selector: 'car-list',
template: `
<h1>Add Car</h1>
<form (submit)="saveCar()">
<input required [(ngModel)]="name" placeholder="Add car">
</form>
<br>
<table>
<tr *ngFor="let car of cars" >
<td>{{car.name}}</td>
<td><button (click)="goToDetail(car)">Detail</button></td>
</tr>
</table>
`,
})
export class ListComponent implements OnActivate {
id: string
name: string;
cars: Array<Car>
constructor(public _service: Service, public _router: Router) { }
routerOnActivate(): void {
this._service.getCars()
.subscribe(cars => this.cars = cars);
}
saveCar() {
let car = new Car(this.id, this.name)
this._service.saveCar(Car)
.subscribe(car => this.cars.push(car));
this._service.getCars()//
.subscribe(cars => this.cars = cars);
}
goToDetail(car:Car) {
this._router.navigate(['/cardetail', car.id]);
}
}
The problem I have is in the detail-component, where the user gets navigated after clicking a specific car. The routing and retrieving the Car from the db works as it should. That I know, because if I remove all the template except <h1>Car: {{car?.name}}</h1> the name gets printed out fine with the elvis operator.
But my detail-component looks something like this:
#Component({
selector: 'car-detail',
template: `
<h1>Car: {{car?.name}}</h1>
<hr>
<button (click)="addBrand()">Add Brand</button>
<div *ngFor="let brand of car.getBrands(); let i=index">
<h2>Brand {{i+1}}</h2>
</div>
`,
})
export class DetailComponent implements OnActivate {
#Input() car: Car;
constructor(public _service: Service, public _router: Router) { }
routerOnActivate(curr: RouteSegment): void {
let id = curr.getParam('id');
this._service.getById(id)
.subscribe(car => {
this.car = car;
});
}
addBrand() {
this.car.getBrands().push(new Brand());
}
//some other methods
}
So in my detail component I call all methods like: car.someMethod() and further on the nested Brand object like: brand.someMethod() in the template. So the error comes at the call of the method e.g in the template 'cannot get getBrands of undefined' I've tried putting the elvis operator like this: car?.getBrands() It doesn't work. I've tried to wrap the whole thing in a div, both with elvis operator and a <div *ngIf = "car"></div>, doesn't work. Even tried with <template *ngIf="car"></template>, well that doesn't work either....
Edit: my mess-up, wrapping like below, it does "kind of" work, meaning, it gives a new error....
Template:
#Component({
selector: 'car-detail',
template: `
<h1>Car: {{car?.name}}</h1>
<hr>
<button (click)="addBrand()">Add Brand</button>
<div *ngIf="car">
<div *ngFor="let brand of car.getBrands(); let i=index">
<h2>Brand {{i+1}}</h2>
</div>
</div>
You mention <h1>Car: {{car?.name}}</h1> with ? but the full code example has <td>{{car.name}}</td> without ? which will cause an error.
<div *ngFor="let brand of car.getBrands(); let i=index">
also needs a ? to avoid errors when Angular tries to render the view and car is not yet set
<div *ngFor="let brand of car?.getBrands(); let i=index">
I am using Angular 2.0.0-beta.0 and TypeScript 1.7.5
When you type something in the search box and something is found and shown on the screen, then you delete the search input box and you want to show an empty list. It work using this piece of code:
this.searchTermStream.next("makesureyoudontfindanything");
Does anyone has a better cleaner solution without doing a http request?
#Component({
selector: 'contact-search',
template: `
<div class="container">
<div class="form-group">
<label for="inputUser">Search</label>
<input #inputUser (keyup)="search(inputUser.value)">
</div>
<ul>
<li *ngFor="#contact of contactList | async">{{contact.name}}</li>
</ul>
</div>
`
})
export class ContactSearch {
private searchTermStream = new Subject<string>();
private contactList: Observable<Contact[]> = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((value: string) => this.contactService.searchContacts(value))
constructor(private contactService: ContactService) {}
search(value: string) {
if (value) {
this.searchTermStream.next(value);
}
else {
this.searchTermStream.next("makesureyoudontfindanything");
}
}
}
You can check if value is empty before calling service:
private contactList: Observable<Contact[]> = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((value: string) =>
0 < value.length ? this.contactService.searchContacts(value) : Observable.of([]))
search(value: string) {
this.searchTermStream.next(value);
}