How to break line with TypeScript - html

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.

Related

angular service/config to populate text as required into component but want to add html also

service/config file:
import { Injectable } from "#angular/core";
import { SafeHtml } from "#angular/platform-browser";
#Injectable()
export class xxxxxConfig {
xxxVaultLink: SafeHtml;
whatHappensNextItemsForEmailxxx: string[];
whatHappensNextItemsForEmailSubTextxxx: string[];
constructor() {
this.xxxVaultLink = `xxx xx`;
this.whatHappensNextItemsForEmailxxx = [
`Confirmation of payment and a copy of your receipt has been emailed to you. You should receive it shortly.`,
`xxxx will send your xxxxxdocuments (xxxxx) by post within 5 days.`,
`A copy of your renewal xxxxx along with any supporting docs can be found in your
${this.xxxVaultLink} within the next 2 - 3 days.`,
];
this.whatHappensNextItemsForEmailSubTextxxx = [
`(If you wish to receive your receipt by post, please contact us on 08xxxxx)`,
`Important: please ensure that you keep your documents safe as they form the basis of your xxxx with xxx.`,
``,
];
}
I'm trying to add a link to the third item in the array above i.e. ${this.xxxVaultLink} but it shows all of the html including tags i.e. <\a href="https://www.w3schools.com" target="_blank">xxx xx</a>
Accessing it from the component below
Component file:
whatHappensNext() {
if (!this.isxxxxy) {
this.whatHappensNextItems = this.isxxxxPhoneNumber
? this.xxxxConfig.whatHappensNextItemsForEmailxxx
: this.xxxxConfig.whatHappensNextItemsForPost;
this.whatHappensNextItemsSubText = this.isxxxxPhoneNumber
? this.xxxxConfig.whatHappensNextItemsForEmailSubTextxxx
: this.xxxxConfig.whatHappensNextItemsForPostSubText;
}
}
Not sure if this makes sense but it would be great if one of you guys could tell me how to display the html/link in this config/service file
You're missing possibly the most important part, which is the template showing us how you're attempting to show these string values.
I'll take a stab in the dark and assume it's something like this:
<div>{{myText}}</div>
If you want to slap some HTML in there, try this:
<div [innerHTML]="myText"></div>

Best approach to deal with JSON responses in the Front End/Angular when subscribing it as a forkJoin?

I have read multiple answers to these kind of issues, and each answer has its own response;
In my case I am not getting any of those as my interfaces simply don't map the json like I want it to. I have tried multiple solutions, since working with Root-object and nested interfaces, but here I am, asking which is the best approach to deal with these kind of JSON objects in the front end, how to map it this particular one (a fork-Join). and I wanted to ask what are the real benefits of using the interfaces/classes/ maps besides the Intellisense? It has to do with data propagation?
The json structure in question:
{
Title: "",
Year: "",
Rated: "",
Released: "",
Runtime: "", 
…}
Simple as it is. But back in my service I call it with a forkjoin:
getMovies(name: string, year?: string): Observable<any> {
let shortPlot = this.http.get(
"https://www.omdbapi.com/?t=" +
name +
"&plot=short&y=" +
year +
"&apikey=[my key]"
);
let fullPlot = this.http.get(
"https://www.omdbapi.com/?t=" + name + "&plot=full&apikey=[my key]"
);
return forkJoin([shortPlot, fullPlot]);
}
The subscription in the component:
getMovie() {
this.spinner = true;
this.movieService
.getMovies(this.name.value)
.subscribe((dataList: any) => {
this.movies = Array.of(dataList[0]);
this.spinner = false;
let error: any = this.movies.map(error => error.Error);
if (error[0]) {
this.notfound = error[0];
this.error = true;
} else {
this.error = false;
this.movieRate = this.movies.map(rating => rating.imdbRating.toString());
}
})),
error => console.log(error);
}
And in the HTML I render the data like this:
<div *ngFor="let m of movies">
<h5 class="mt-0">{{m.Title}}, {{m.Year}}</h5>
</div>
So as you can see I am not working with an interface and I should. Anyone can sort me out?
Thank you
EDIT: the log after subscribe:
let's break it down,
what are the real benefits of using the interfaces/classes/ maps besides the Intellisense?
Using interfaces and classes will not just give you intellisense but will also provide static type safety for your code. Why this is important, let's say you have a interface with following structure,
export interface Demo {
field: string;
}
// in some other file 1
demo.field.substring(1, 2);
// in some other file 2
demo.field.lenght;
You are using this interface in many places in your code. Now, for some reason you get to know that the property should be number not string. So here typescript will give you all the errors at compile time only.
export interface Demo {
field: number;
}
// in some other file 1
demo.field.substring(1, 2); // error
// in some other file 2
demo.field.lenght // error
Also, after typescript transpiles it will generate javascript files, now as javascript is interpreted language, your code will not be tested until the javascript run-time actually executes the problematic line, but in typescript you will get errors in compilation stage only.
You can get away with using any everywhere, but with that you will be missing the static typings.
With interfaces and classes, you also get OOP features, such as inheritance etc.
It has to do with data propagation?
Your frond-end is never aware what type of data will be received from api. So it's developers responsibility that the received data should be mapped to some interface.
Again as mentioned above, if somehow back-end changes type of some field in received json, then it will again be caught in compile time.
In case of forkJoin which combines output of two jsons you can have two different types.
Demo
export interface Demo1 {
field1: string;
}
export interface Demo2 {
field2: number;
}
// in service layer
getData(): Observable<[Demo1, Demo2]> {
const res1 = this.http.get(...);
const res2 = this.http.get(...);
return forkJoin([res1, res2]);
}
// in component
this.dataService.getData().subscribe(res => {
// you will get type safety and intellisense for res here
console.log(res[0].field1)
})
I am not working with an interface and I should.
Yes, you should use interfaces, if you are not using using features of typescript then whats the point using it. :)

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}.

Angular2 Is it possible to get deep nested json value without using ngFor?

I am currently getting json object from server and the object also has many nested json object as well. So far, I've been using *ngFor = "let a of data | pipe" (the pipe to get deeply nested value) and single interpolation {{a.value['someValue']}} to get the deep nested value of json object for other situations but this isn't serving my purpose right now since I don't want to loop my json.
Is there any way to get deeply nested json value without using ngFor?
The part of json object I am getting from server.
UserProfile:
{name: 'Jess'
University: 'UC Berkley'
Major: 'Media Communication'
birthday: 1994}
categoryInfo:
["inish work with quality"]
currentArea
:"CA"
introInfo {
experience: [
0: {Company: 'Atlas', workingYears: 1, **recLetter**:'She was on time always,
never late. The quality of her work is very high-level.'}
1: {Company: 'Footstep', workingYears: 2, recLetter:'She was on time always,
never late. The quality of her work is very high-level.'}
]
introduction: "Hello I'm Jess"
}
And if I use aforementioned method, it will just loop 4 keys (UserProfile, categoryInfo, currentArea, and introInfo) which I don't want.
How can I get value that's in bold (recLetter) without using *ngFor?
in my component, I am doing this.
userInfo: UserDetailInfo[];
getUserDetail(): void {
this.userDetail.getUserDetail()
.subscribe
(
userInfo => this.userInfo = userInfo,
error => this.errorMessage = error
)
}
And I tried this in the html template but didn't work and I didn't know how to get 'recLetter'
{{userInfo.experience['0']}}
Please help!
Thank you in advance
For the starters, lets assume you get experience array always the same, with 2 elements.
The only thing that you need to do in the html is this:
{{ userInfo.experience[0].recLetter }}
In case you want to loop through the whole array exeperience and display recLetter you can do this:
<div *ngFor="let item of userInfo.experience">
{{item.recLetter}}
</div>
Try this
properties.pipe.ts
import {Pipe} from '#angular/core';
#Pipe({name: 'properties'})
export class PropertiesPipe {
transform(o: {}) {
return Object.entries(o).map(([key, value]) => ({
key,
value
}));
}
}
app.module.ts
import {propertiesPipe} from './properties.pipe';
#NgModule({
declarations: [PropertiesPipe, /* whatever else was here */],
// ... whatever else was here
}) export class AppModule { }
component.html
<ul>
<li *ngFor="property of userInfo | properties">
<span *ngIf="!Array.isArray(property.value)">
{{property.key}}: {{property.value}}
</span>
<span *ngIf="Array.isArray(property.value)">
{{property.key}}: <span *ngFor="value of property.value">{{value}}, </span>
</span>
</li>
</ul>

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.