How to get data from observable? - angularjs

Im trying to get some data from a request. I have an observable function that gives me the data inside of .subscribe, but whenever i try to get that data outside ( in a variable defined in the class) it will return me undefined and its quite annoying
Component.ts:
import { ProjectService } from '../services/project.service';
#Component({
selector: 'app-project-loader',
templateUrl: './project-loader.component.html',
styleUrls: ['./project-loader.component.css']
})
export class ProjectLoaderComponent implements OnInit {
projects:any;
constructor(private projectService: ProjectService) { }
ngOnInit(): void {
this.getProjects();
}
getProjects(){
this.projectService.getProjects().subscribe(data=>{
this.projects= data;
})
}
}
Component.html:
{{projects[0].id}}
The html is just for testing porpouses right now, so it has only 1 line. FYI the data returned in the observable function is an json array.
Array Example:
{
"id": "REDACTED",
"projectName": "REDACTED",
"projectId": "REDACTED"
},
{
"id": "REDACTED",
"projectName": "REDACTED",
"projectId": "REDACTED"
}
]
(Redacted are strings from a private db :P)

I solved it myself. I just had to use a *ngFor to encapsulate the projects like this:
<div *ngFor=" let project of projects">
<button class="list-group-item list-group-item-action" (click)="openProject(project.id)" >{{project.projectName}}</button>
</div>

Related

changed attributes not waving with Wordpress block

I have a fairly simple block in a plugin, built using npx #wordpress/create-block pn-DisplayBlocks. Attributes, in block.json, are:
(code changed as per fixes below)
"attributes": {
"pid": {
"type": "text",
"default": "444"
}
}
save.js is:
import { __ } from '#wordpress/i18n';
import { useBlockProps } from '#wordpress/block-editor';
export default function Save( {attributes} ) {
console.log( "SAVING", attributes )
return (
<p { ...useBlockProps.save() }>
{ __( 'Pn Image – hello from the saved content! ' + attributes.pid, 'pn-image' ) }
</p>
);
}
and edit.js is:
import { __ } from '#wordpress/i18n';
import { useBlockProps } from '#wordpress/block-editor';
import './editor.scss';
import { __experimentalNumberControl as NumberControl } from '#wordpress/components';
export default function Edit( {attributes, setAttributes} ) {
console.log( "pid", attributes.pid )
return (
<p { ...useBlockProps() }>
{
__( 'Pn Image – hello from the editor! ' + attributes.pid, 'pn-image' )
}
<NumberControl
label="PID"
isShiftStepEnabled={ true }
onChange={ value => { setAttributes( {pid: value})} }
shiftStep={ 10 }
value={ attributes.pid }
/>
</p>
);
}
NumberControl value updates pid and the block with the correct number value when changed, that all works fine, but if I preview the page I see the default value of pid showing, not the one I've just change it to. Same if I update the page to save it; console.log shows the new pid value but when reloaded into the edit page, pid reverts to the default value. Maybe I'm staring too hard but for the life of me I can't see what's wrong. Also, I'm fairly new to this so I may be doing something idiotic.
save & edit called from registerBlockType in index.js:
import { registerBlockType } from '#wordpress/blocks';
import './style.scss';
import Edit from './edit';
import Save from './save';
registerBlockType( 'pn-displayblocks/pn-image', {
edit: Edit,
save: Save,
} );
Attributes in block.json:
{
"apiVersion": 2,
"name": "pn-displayblocks/pn-image",
"version": "0.1.0",
"title": "Pn Image",
"category": "widgets",
"icon": "smiley",
"description": "Example block written with ESNext standard and JSX support – build step required.",
"supports": {
"html": false
},
"textdomain": "pn-displayblocks",
"editorScript": "file:./build/index.js",
"editorStyle": "file:./build/index.css",
"style": "file:./build/style-index.css",
"attributes": {
"pid": {
"type": "text",
"default": "444"
}
}
}
Did you try to store your attributes in comments of block ?
In according with documentation gutenberg :
The available source values are:
– (no value) – when no source is specified then data is stored in the block’s comment delimiter.
– attribute – data is stored in an HTML element attribute.
– text – data is stored in HTML text.
– html – data is stored in HTML. This is typically used by RichText.
– query – data is stored as an array of objects.
– meta – data is stored in post meta (deprecated)
Can you try with ?
"pid": {
"type": "text",
"default": "444"
}

Not able to Query hyperlinks from GraphQL on Gatsby JS

I'm working on a Blog on Gatsby JS, and I'm having an issue with the hyperlinks, and I'm not able to solve it.
I have the following query
const options = {
renderNode: {
"embedded-asset-block": (node) => {
const alt = node.data.target.fields.title['es']
const url = node.data.target.fields.file['es'].url
return <img alt={alt} src={url} />
},
[INLINES.HYPERLINK]: (node) => {
if(node.data.uri.indexOf('youtube.com') !== -1){
return(
<iframe width="560" height="315" src={node.data.uri} frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
)
}else{
return(
<a href={node.data.uri}>{node.content.value}</a>
)
}
}
}
}
From this query, I'm able to add assets and youtube videos. The issue is, that when I add a hyperlink, they are shown on the page but without text.
I only see the and not the text of this link.
I know the problem is here <a href={node.data.uri}>{node.content.value}</a>, but I'm not able to query the value.
This is GraphQL:
"body": {
"json": {
"nodeType": "document",
"data": {},
"content": [
{
"nodeType": "paragraph",
"content": [
{
"nodeType": "text",
"value": "Desde ",
"marks": [],
"data": {}
},
{
"nodeType": "hyperlink",
"content": [
{
"nodeType": "text",
"value": "FelixDigital",
"marks": [],
"data": {}
}
I need to query the value (FelixDigital)
Does anybody can help me?
Thank you so much,
Can you do a debugger inside this code?
It's hard to say.. but what I would check is the value of node. To me it looks like content is an array and inside the first item of the array you have value so to me it should look more like node.content[0].value.
I'm guessing you are using Contentful to pull your data into your blog using GraphQL. With Contentful you must use documentToReactComponents on JSON nodes (all rich text items). To obtain FelixDigital, you may want to do something instead like:
import { documentToReactComponents } from '#contentful/rich-text-react-renderer';
return(
<div>
{documentToReactComponents(videos.videoItem.videoLinks.json, options)}
</div>
)
This will then use the iframe you set up in const options and grab the src uri.
More info can be found here on rendering rich text with contentful

Angular dynamic array showing all results not just data under id

I am still trying to learn what seems to me like advanced Angular 5. The below code does enter the "id" number from the array into the url as expected, but when I go to model/1 it shows my all the objects from the array. I need to only see the object under id 1 and same for each object in the array. I have found so much conflicting information online, from mapping to queries that I'm not even sure where to being and everything I've tried has led to no better results. I have included all the code I'm working with.
I have an array of objects in my json file-
[
{
"id": 1,
"label": "Metal Man",
"sample": "/assets/img/metalman1.png",
"fab": "https://sketchfab.com/models/1b3cb7f8a77145bc8616075e9036b025/embed",
"img1": "/assets/img/metalman1.png",
"img2": "/assets/img/metalman2.png",
"img3": "/assets/img/metalman3.png"
},
{
"id": 2,
"label": "Magrot",
"sample": "/assets/img/magrot1.png",
"fab": "https://sketchfab.com/models/e20c8ade2f16452ca7f440aa84fc8e33/embed",
"img1": "/assets/img/magrot1.png",
"img2": "/assets/img/magrot2.png",
"img3": "/assets/img/magrot3.png"
},
{
"id": 3,
"label": "Baseball and Bat",
"sample": "/assets/img/ball1.png",
"fab": "https://sketchfab.com/models/781c60d3449b46f996a081ae36c20cce/embed",
"img1": "/assets/img/ball1.png",
"img2": "/assets/img/ball2.png",
"img3": "/assets/img/ball3.png"
}
]
My template for each of the above objects-
<div class="columnFlex mainBlock" *ngFor="let model of modelwork">
<div class="modelImagery">
<h1>{{ model.label }}</h1>
<iframe [src]='sanitizer.bypassSecurityTrustResourceUrl(model.fab)'
frameborder="1" allowvr allowfullscreen mozallowfullscreen="true"
webkitallowfullscreen="true" onmousewheel=""></iframe>
<img [src]="model.img1" />
<img [src]="model.img2" />
<img [src]="model.img3" />
</div></div>
And my Activatedroute set up-
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { CommonModule } from '#angular/common';
import { DomSanitizer } from '#angular/platform-browser';
import { ActivatedRoute } from '#angular/router';
import { Router } from '#angular/router';
#Component({
selector: 'app-model',
templateUrl: './model.component.html',
styleUrls: ['./model.component.css']
})
export class ModelComponent implements OnInit {
modelwork: any;
constructor( private route: ActivatedRoute, private router: Router, private http: HttpClient, public sanitizer: DomSanitizer ) {
this.sanitizer = sanitizer;
this.route.params.subscribe(params => {this.modelwork = params['id'];});
}
ngOnInit(): void {
this.http.get<any>('./assets/models.json').subscribe(
data => {
this.modelwork = data;
})
}
}
Any clarification on what I'm needing to do would be so appreciated! I'm trying to learn Angular in days and it is more complicated than I had expected. Thank you for taking the time to look at this!
I don't see anything advanced here. You simple have two asynchronous operations that both set the variable 'modelwork'. One of the operations sets modelwork to an integer and the other sets it to a json array. depending on which operation resolves first.
Edit
Looking at your comment, i see what you want to do. Here's an example:
chosenIndex: any;
modelwork: any;
constructor( private route: ActivatedRoute, private router: Router, private http: HttpClient, public sanitizer: DomSanitizer ) {
this.sanitizer = sanitizer;
}
ngOnInit(): void {
this.route.params.subscribe(params => {
this.chosenIndex = params['id'];
this.http.get<any>('./assets/models.json').subscribe(data => {
this.modelwork = data.filter(d => d['id'] == this.chosenIndex);
})
});
}
Modelwork will now contain an array of 1 object. The one object you want. You can alter this example to get whatever output you want.

Strange behaviour of TypeScript String.split() function

I have TypeScript model like this:
export class Product {
id:number;
name:string;
brand:Brand;
price:number;
shippingPrice:number;
description:string;
photoName:string;
productType:ProductType;
purchaseCounter:number;
rating:number;
volume:string;
ingredients:string;
}
and json file which populate this model:
{
"id": 1,
"name": "xxx",
"description": "xxx",
"price": 12.34,
"purchaseCounter": 12,
"photoName": "xx",
"shippingPrice": 12.99,
"volume": "xxx",
"rating": 4.7,
"ingredients": "A,B,C",
"brand": {
"id": 1,
"name": "xx"
},
"productType": {
"id": 3,
"name": "xxx"
}
}
Now in my TypeScript component I have function like this :
public getIngredients():String [] {
return this.product.ingredients.split(",");
}
Everytime when I am invoking this function I have error:
"TypeError: Cannot read property 'split' of undefined"
but when i change body of function to sth like this:
public getIngredients():String [] {
if (this.product.ingredients == null) {
return null;
}
return this.product.ingredients.split(",");
}
then eveyrthing is ok and split function work properly. Have You got any idea why checking if ingredients is not null fix it? I have to admin that I just start my adventure with js and ts. Thanks
UPDATE
I instantiating this Product variable here:
export class ProductOverviewComponent implements OnInit {
private product:Product;
private errorMessage:string;
constructor(private productService:ProductService) {
this.product = new Product();
}
ngOnInit():void {
this.productService.getProduct()
.subscribe(
product => this.product = product,
error => this.errorMessage = <any>error);
}
}
For now I hit to the json file but in future I will hit to server. Another think is that I pass product to another comopnent using #Input().
And this is how i call getIngredients function
<div class="col-md-12">
<div class="property-text">
<!--<h3 class="h3style">Ingredients</h3>-->
<ul>
<li *ngFor="let ingredient of getIngredients()">
{{ ingredient }}
</li>
</ul>
</div>
</div>
The TypeError that you get is a JavaScript error raised at runtime and has nothing to do with TypeScript. It happens because this.product.ingredients is undefined. Your "fix" works because undefined == null is true in JavaScript which results in an early return inside getIngredients(). If you used the === operator to compare against null your fix would no longer work.
However, the question is then why this.product.ingredients is undefined? It may be because the TypeScript this context is lost inside getIngredients(). From the code you have provided it is impossible to determine if that is the case but there is a nice write-up about the problem in the 'this' in TypeScript article on Github which might help you solve your problem. A simple first check could be to add console.log(this) inside getIngredients() to see what this really is.

Looping through array of object data within Falcor

Let's say I have the following routes:
{
route: "usersById['length']",
get: function(pathSet) {}
},
{
route: "usersById[{integers:ids}]['firstName', 'lastName']",
get: function(pathSet) {}
}
With the following in my angular1 controller:
Model.get(
'usersById.length',
'usersById[0..2]['firstName', 'lastName']'
).then(function(response) {
$scope.$apply(function() {
vm.entities = response.json.usersById;
});
});
The response from the server is going to look something like:
{
jsonGraph: {
usersById: {
"0": {
firstName: 'Jiminy',
lastName: 'Cricket'
},
"1": {
firstName: 'Jafar',
lastName: 'Husain'
},
"length": 123123
}
}
}
In my angular 1 template, I want to loop through the list of users:
<tr ng-repeat="entity in users.entities">
<td>{{entity.firstName}} {{entity.lastName}}</td>
</tr>
The problem is that there aren't just users in the response, firstly it contains length and secondly it seems other meta data is returned by Model's promise, of which looks to be part of the path data: usersById
What is the preferred way of looping through the list of users? Should I doing something like this in my promise?
vm.entities = response.json.usersById.filter(function(value) {
return typeof value === 'object';
});
I'm not seeing any API call for fetching raw values anywhere.
Ok so it seems the correct way to handle this is to create another route: users which just returns usersById references, that way you have an array of just entities, not containing length etc.
I'm guessing having the path data in the array of data was just a bug.
{
users: {...},
usersById: {...}
}
<li ng-repeat="user in users">{{ user.firstName }}</li>

Resources