Change attribute dynamically angular from Json - json

I am trying to change the [icon]="ractAtom" to use a value from Json but it does not seem to work. Please, could someone help with this. In other words, the [icon]'s value should be based on the 'featureItem' that is being received from the parent
HTML
<div>
<fa-icon [icon]="reactAtom" class="icon-automation"></fa-icon>
<h3>{{featureItem.name}}</h3>
<p class="card-title-features">{{featureItem.description}}</p>
<hr class="line-separator">
<accordion closeOthers="true" *ngFor="let accGroup of featureItem.accorditions">
<accordion-group [isOpen]="false" #accordionGroupRef>
<span accordion-heading style="display:flex;justify-content:space-between;align-items:center">
<div>
<fa-icon [icon]="heart"></fa-icon> <span class="card-title-accordtion">{{accGroup.accorditionTitle}}</span>
</div>
<fa-icon *ngIf="accordionGroupRef.isOpen" [icon]="caretDown"></fa-icon>
<fa-icon *ngIf="!accordionGroupRef.isOpen" [icon]="caretUp"></fa-icon>
</span>
<p>{{accGroup.accordtitionDescription}}</p>
</accordion-group>
</accordion>
</div>
TS
import { Component, Input, OnInit } from '#angular/core';
import {faReact} from '#fortawesome/free-brands-svg-icons';
import {faPeopleGroup, faBullseye, faHeart,faCaretUp, faCaretDown} from '#fortawesome/free-solid-svg-icons';
#Component({
selector: 'app-features-item',
templateUrl: './features-item.component.html',
styleUrls: ['./features-item.component.scss']
})
export class FeaturesItemComponent implements OnInit {
#Input() featureItem:any;
reactAtom = faReact;
peopleGroup = faPeopleGroup;
bullseye = faBullseye;
heart = faHeart;
caretDown = faCaretDown;
caretUp = faCaretUp;
constructor() { }
ngOnInit(): void {
}
}
Here is the JSON that I am using:
featuresJson = [
{
"name":"Automation",
"mainIcon":"reactAtom",
"mainIconClass":"icon-automation",
"description": "Automate admin work and cut costs by 60%",
"accorditions":[
{"icon":"heart",
"accorditionTitle":"Complience",
"accordtitionDescription":"Certify employees on the latest policy and regulatory requirements."
},
{"icon":"heart",
"accorditionTitle":"HCM Sync",
"accordtitionDescription":"Streamline the learning experience for employees and administrators."
},
{"icon":"heart",
"accorditionTitle":"Live",
"accordtitionDescription":"Schedule training sessions, increase fill rates & verify attendance digitally."
}
]
},
{
"name":"Enablement",
"mainIcon":"peopleGroup",
"mainIconClass":"icon-enablement",
"description": "Enable client-facing teams to over perform",
"accorditions":[
{"icon":"heart",
"accorditionTitle":"Mobile Advanced",
"accordtitionDescription":"Provide frontline teams with shared device access, video evaluation & mobile content creation."
},
{"icon":"heart",
"accorditionTitle":"Coaching",
"accordtitionDescription":"Boost confidence and performance through Coaching."
},
{"icon":"heart",
"accorditionTitle":"Extended Enterprise",
"accordtitionDescription":"Onboard new clients, partners & other non-employees in your 360Learning environment."
},
{"icon":"heart",
"accorditionTitle":"Software Adoption",
"accordtitionDescription":"Turn your team into tool experts with interactive training experiences."
}
]
},
{
"name":"Development",
"mainIcon":"bullseye",
"mainIconClass":"icon-development",
"description": "Make professional growth a pillar of your company's culture",
"accorditions":[
{"icon":"heart",
"accorditionTitle":"Onboarding",
"accordtitionDescription":"Make sure new employees hit the ground running and ramp-up quickly."
},
{"icon":"heart",
"accorditionTitle":"Curated Programs",
"accordtitionDescription":"Give learners access to catalogs of best-in-class courses."
}
]
}
]
So, I was trying to do the following but it would simply not work. I'd appreciate any input.
<fa-icon [icon]="[featureItem.mainIcon]" class="icon-automation"></fa-icon>

First off I would recommend to create an interface to represent this structure so you can type your variables (#Input() featureItem).
Next, this
<fa-icon [icon]="[featureItem.mainIcon]" class="icon-automation"></fa-icon>
should be
<fa-icon [icon]="featureItem.mainIcon" class="icon-automation"></fa-icon>
Those brackets are incorrect.
Sidenote:
You can remove all the quotes around the property names in the object. It is a javascript object. If you originally have a JSON (e.g. you had a http response) you can either use implicit type casting (with an interface) or explicitly use JSON.parse.

Related

How does the variable linking work in TypeScript?

I am new at Angular and now I am currently being stucked, because I can not understand why it works like that. Here is my code ⬇️
🪧 Explonation of whole functionality:
I have a mock list of heroes in another file (mock.heroes.ts), where the whole list is set like const value, what means you can not change it anymore. Everything works well, also it's understandable for me, till you select, by clicking on exact hero, your selectedHero. The div is now visible, and you can change its name in the input field below.
❓ I can not understand, why when I change something inthe input with the id="hero-name", the change occurs not only on selectedHero.name but also on hero.name (in the ul with class="heroes").
❓ Is this.selectedHero like link to real hero, or how does this binding works in TS? At first I thought, selectedHero was a copy of a hero. That's why I am asking, because it does not make sence for me.
❓ Why even after the list is set to be const value, you can change the names of the heroes init?
___.component.html
<ul class="heroes">
<li
*ngFor="let hero of heroes"
(click)="onSelect(hero)"
[class.selected]="hero === selectedHero">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<div *ngIf="selectedHero">
<h2>{{selectedHero.name | uppercase}} Details</h2>
<div><span>id: </span>{{selectedHero.id}}</div>
<div>
<label for="hero-name">Hero name: </label>
<input id="hero-name" [(ngModel)]="selectedHero.name" placeholder="name">
</div>
</div>
___.component.ts
import { Hero } from '../hero';
import { HEROES } from '../mock-heroes';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes = HEROES;
selectedHero?: Hero;
constructor() { }
ngOnInit(): void {
}
onSelect(hero: Hero) {
this.selectedHero = hero;
}
}
mock.heroes.ts
import { Hero } from './hero';
export const HEROES: Hero[] = [
{ id: 11, name: 'Dr Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
];
I can not understand, why when I change something inthe input with the id="hero-name", the change occurs not only on selectedHero.name but also on hero.name (in the ul with class="heroes")
Angular runs checks every now and then to look for updates on your models. If a change is detected, the view is updated, this is why your content changes elsewhere.
Is this.selectedHero like link to real hero, or how does this binding works in TS? At first I thought, selectedHero was a copy of a hero. That's why I am asking, because it does not make sence for me.
It's the same object, they share the same address. If you want to deepcopy your object, call JSON.parse(JSON.stringify(myJSONobject))
Why even after the list is set to be const value, you can change the names of the heroes init
What const keyword does is protect your variable from changing it's address. Let's say you have an array at address A having multiple objects in it. Each an every object has it's own address (B, C, D, ...). So as long as you don't reasign that const variable you are good to go. nothing hold you from changing the inner content of this array. Reassign it is what wouldn't work using the const keyword.
It is the so called two way binding underneath. You change that object by entering a name. Because that object has changed, that triggers the rerendering of that one object in the ul and you got the magic happened 😉. Read here: https://angular.io/guide/two-way-binding

How to break line with TypeScript

I am new to angular and I am trying to do a random quote generator. I got inspired from a tutorial and everything is fine until now but I want to add a line break between the quote and the author.
What I have:
Don't Let Yesterday Take Up Too Much Of Today. - Will Rogers
What I want:
Don't Let Yesterday Take Up Too Much Of Today.
Will Rogers
I have this code so far in my app.component.ts:
quotes = [
'The Pessimist Sees Difficulty In Every Opportunity. The Optimist Sees The Opportunity In Every Opportunity',
"Don\'t Let Yesterday Take Up Too Much Of Today. -Will Rogers",
'You Learn More From Failure Than From Success. Don\'t Let It Stop You'
]
getNewQuote() {
const quoteText = document.querySelector('.quote-text');
this.randomNumber = Math.floor(Math.random() * (this.quotes.length));
quoteText.textContent = this.quotes[this.randomNumber];
quoteText.textContent = this.quotes[this.randomNumber].split("-");
}
I tried
quoteText.textContent = this.quotes[this.randomNumber].split("-");
But is is just giving me:
Don't Let Yesterday Take Up Too Much Of Today. , Will Rogers
I looked for line break with typescript but none of what I did is working. How can i do it?
You are using TypeScript to generate the contents of an HTML page. Hence, your ultimate output is supposed to be HTML code. To break lines in HTML, use the <br> tag.
The output generated by your TypeScript code should be something like this:
<p>First Line.<br>Second Line</p>
Here is some reference.
It can be solved by just adding \n at the point where you want to break the quote.
//By adding \n in the text you can Break the line. Happy Coding!
var test = "Hello\nWorld";
console.log(test);
If you are setting up the quotes yourself, you can separate the author from the quote from the start.
I won't recommend using a regexp or split() to chunk a string in pieces unless you know very precisely where to split your string and that it never fails or splits at the wrong place.
example
Stackblitz: https://stackblitz.com/edit/angular-ivy-ogfspj?file=src/app/app.component.ts
app.component.ts
import { Component, OnInit } from '#angular/core';
interface Quote {
quote: string;
author: string;
}
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
public quote: Quote;
private quotes: Quote[];
ngOnInit(): void {
this.quotes = [
{
quote: 'The Pessimist Sees Difficulty In Every Opportunity. The Optimist Sees The Opportunity In Every Opportunity',
author: 'unknown'
}, {
quote: 'Don\'t Let Yesterday Take Up Too Much Of Today',
author: 'Will Rogers'
}, {
quote: 'You Learn More From Failure Than From Success. Don\'t Let It Stop You',
author: 'unknown'
}
]
this.random_quote()
}
private random_quote(): void {
const index = Math.floor( Math.random() * this.quotes.length );
this.quote = this.quotes[index];
}
}
app.component.html
<blockquote>
<i>{{quote.quote}}</i><br><br>
- {{quote.author}}
</blockquote>
takeaways for beginners
The big takeaways for beginners from this example would be:
use an interface to define a Quote type, this will be easier to work with
bind a property using {{}}
most of the time you want to initialise data in the ngOnInit lifecycle hook; You will probably refactor this code at some point to get the quotes from a service. Then you need to initialise quote in this hook.

Angular 6 return JSON result intead of HTML template

Is it possible to return JSON result from Angular instead of the HTML template coz we want to build something similar to a API-server? Thanks.
Here is the example that return the HTML template, how can we just return JSON without using template?
What I want to return is just a simple json result instead of HTML.
{"ID" : "1", "Name" : "Apple"}
Here is the code.
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-noresultsfound',
templateUrl: './noresultsfound.component.html',
styleUrls: ['./noresultsfound.component.css']
})
export class NoresultsfoundComponent implements OnInit {
#Input() txtval: string;
constructor(private app: AppConstants) { }
noresultsfound = this.app.noresultsfound;
ngOnInit() {
}
}
Alex
I think, he meant that pure JSON should be returned to who ever requested it by endpoint request. At least i faced something like this.
For static json, i've found an answer: https://github.com/angular/angular-cli/issues/5029
bresleveloper commented on 6 Jul 2018
1. ng-build with your index.html set properly with its components. (or conditional app-components)
2. rename and copy the rendered to (for example) /src/search.html
3. in angular.json (angular-cli.json for pre v5) find "assets":
"assets": [
"src/favicon.ico",
"src/search.html",
"src/assets"
],
browse localhost:4200/search.html
enjoy :)
Interesting part comes when u try to generate that json somehow, with browser not being involved - like some automatic service sends a request to some angular endpoint, like: hosname/statistics and in response, it receives a json which depends on number of pictures and headers on this current hosname, like {siteName: 'test', pictures: 10, headers: 1}.

Extract key-value combo from json object

I have the following object that gets returned from an API fetch
{
id: 1,
name: "Leanne Graham",
zipcode: "92998-3874",
username: "Bret",
email: "Sincere#april.biz",
..... (only the ones above matter to me)
}
I want to extract only certain parts of the objects ( e.g. zipcode ). I tried the following: this.props.users.zipcode JSON.parse JSON.stringify but all of them return undefined when logging to console. Do you mind helping me?
Considering only your data the below possible solution will help you in get the values of the keys.
import React, {Component} from 'react';
export default class Test extends Component {
render(){
let data = [{"id":1,"name":"Leanne Graham","username":"Bret","email":"Sincere#april.biz","address":{"street":"Kulas Light","suite":"Apt. 556","city":"Gwenborough","zipcode":"92998-3874","geo":{"lat":"-37.3159","lng":"81.1496"}},"phone":"1-770-736-8031 x56442","website":"hildegard.org","company":{"name":"Romaguera-Crona","catchPhrase":"Multi-layered client-server neural-net","bs":"harness real-time e-markets"}}]
data.map((d, i) => {
console.log("values", d.name, d.email, d.address.zipcode )
});
return(
<div>
</div>
)
}
}
or
import React, {Component} from 'react';
export default class Test extends Component {
render(){
if(this.props.users && this.props.users.map((d, i) => {
console.log("values", d.name, d.email, d.address.zipcode )
});
return(
<div>
</div>
)
}
}
I read from your comment, that you are using Redux.
The result of an API-fetch should be an action. In the associated reducer, you need to retrieve the payload of the action triggered by the successful request.
As others have pointed out before, it would be easier to answer and not just fire shots in the dark if you provided a code-example

Angular 2 - Using/displaying JSON data fetched through HTTP, or mocked

I'm working on an Angular 2 application, and I'm trying to use JSON data, either local/mocked or fetched via HTTP, and display it on a component. I have an injectable service that will do the fetching/mocking -
import { Injectable } from 'angular2/core';
#Injectable()
export class TestService {
testString:string = "";
testDetails: string = "";
constructor() { }
getTestDetails(): Promise<string> {
this.testDetails = {
"status": "success",
"message": "Data save successful",
"data": {
"Random_Data_1": "Random Data 1",
"Random_Data_2": "Random Data 2"
}
};
return Promise.resolve(JSON.stringify(this.propertyDetails));
}
}
And then I have a component that uses the service via Dependency Injection -
import { Component, OnInit } from 'angular2/core';
import {TestService} from "./test.service";
#Component({
selector: 'test',
templateUrl: './test.component.html',
styleUrls: []
})
export class TestComponent implements OnInit {
testDetails: string = "";
constructor(private testService: TestService) { }
ngOnInit() {
this.display();
}
display(): void {
this.testService.getTestDetails()
.then(
testDetails => {
this.testDetails = JSON.parse(testDetails);
},
errorMessage => {
console.error("Something failed trying to get test details");
console.error(errorMessage);
}
);
}
}
The component HTML -
<div class="content">
<p> Test Details </p>
<p> {{ testDetails.data.Random_Data_1 }} </p>
</div>
The problem is, the HTML is erroring out trying to display the items in the testDetails JSON. I initially used it with md-tabs, so the first try would error out, but the other tabs would read the data fine. Also, the ngOnInit would be called twice when the error occurs. I have narrowed it down to the data coming in and the object types that is causing me the headache.
I know I can create a Details class and declare testDetails of type Details, and then map the JSON data into the class, but the thing is, I want to work with generic data, and only know a few components that will be present in the data. Is there a way to read the JSON, and use the data without having to define a separate class for each scenario ?
I have a plunker with the most basic stuff set up. The actual setup runs fine on my local system up until where I try to access the JSON data in the HTML, at which point the browser throws a cryptic error. The skeleton code doesn't even run on Plunker. That said, the structure in the Plunker defines the structure of my app and the data flow. Plunker with the basic setup
What is the best way to achieve this ? What is the standard/best practice to do this ?
Throwing another option out there, since you asked about best way to achieve this. Might not be the best idea, this is subjective ;) But if I were you...
Thinking about the future, where you will use real backend, it could be nice to use mock json file. If/when you move over to a real backend, you wouldn't basically need to change anything else but the url of the requests :)
So I set up a simple example for you. Here I used Observables, but you can use Promises if you prefer that. Here's more info on HTTP if you want/need to read up on that. Most important thing is that you have the HttpModule imported in your app module.
You have your file with JSON and in your service make http-requests to that:
getTestDetails() {
return this.http.get('src/data.json')
.map(res => res.json())
}
Your display-method:
display() {
this.testService.getTestDetails()
.subscribe(data => {
this.testDetails = data;
});
}
And in the template use the safe navigation operator to safeguard null/undefined values:
<div class="content">
<p> Test Details </p>
<p> {{ testDetails?.data?.Random_Data_1 }} </p>
</div>
Here's a
Demo
As said, this is to give another approach on how to implement the things you want to achieve, and this would probably be my preferred way :)
Use
<p *ngIF="testDetails.data.Random_Data_1 "> {{ testDetails.data.Random_Data_1 }} </p>
This is because there is no data initially.Hope this helps you.