How to fetch data from custom component created #hybris side in Spartacus - sap-commerce-cloud

I created custom component "CustomPromotionComponent" by extending "SimpleCMSComponent" #hybris side. It got rendered on spartacus site.
0: {slotId: "Section2A-Promotion",…}
components: {component: [{uid: "CustomPromotionComponent",…}]}
component: [{uid: "CustomPromotionComponent",…}]
0: {uid: "CustomPromotionComponent",…}
container: "false"
modifiedtime: "2020-07-25T17:58:35.279+05:30"
name: "Custom Promotion Component"
typeCode: "CustomPromotionComponent"
uid: "CustomPromotionComponent"
uuid: "eyJpdGVtSWQiOiJDdXN0b21Qcm9tb3Rpb25Db21wb25lbnQiLCJjYXRhbG9nSWQiOiJlbGVjdHJvbmljcy1zcGFDb250ZW50Q2F0YWxvZyIsImNhdGFsb2dWZXJzaW9uIjoiT25saW5lIn0="
as shown above.
How can I retrieve this data from angular?
I created same component #angular side too but it doesn't work.
i have added my component in .ts file as shown along with this i added my component in custom-page.module.ts also.
import { Component, OnInit, ChangeDetectionStrategy } from '#angular/core';
import { CmsComponentData } from '#spartacus/storefront';
import { CmsService} from '#spartacus/core';
import { CMSCustomPromotionComponent } from '../cms.custom-promotion-component';
#Component({
selector: 'app-custom-promotion',
templateUrl: './custom-promotion.component.html',
styleUrls: ['./custom-promotion.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CustomPromotionComponent implements OnInit {
componentData$: Observable<CMSCustomPromotionComponent> = this.componentData.data$;
constructor( protected componentData: CmsComponentData<CMSCustomPromotionComponent>,
protected cmsService: CmsService) {}
ngOnInit(): void {
console.log(this.componentData$);
}
}
html part:
<p *ngIf="(componentData$ | async) as data" [innerHTML]="data.name"></p>
ConfigModule.withConfig({
cmsComponents: {
CustomPromotionComponent: {
component: CustomPromotionComponent,
}
},
} as CmsConfig)
created cmscustomcomponent by extending cmscomponent.
import { CmsComponent } from '#spartacus/core';
export interface CMSCustomPromotionComponent extends CmsComponent {
container?: string;
}
While rendering on storefront i am getting below error:
core.js:6228 ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[CustomPromotionComponent -> CmsComponentData]:
StaticInjectorError(Platform: core)[CustomPromotionComponent -> CmsComponentData]:
NullInjectorError: No provider for CmsComponentData!
NullInjectorError: StaticInjectorError(AppModule)[CustomPromotionComponent -> CmsComponentData]:
StaticInjectorError(Platform: core)[CustomPromotionComponent -> CmsComponentData]:
NullInjectorError: No provider for CmsComponentData!

You can use https://github.com/SAP/spartacus/blob/develop/projects/storefrontlib/src/cms-components/content/paragraph/ as a reference.
This is the interesting part:
constructor(public component: CmsComponentData<CmsParagraphComponent>) {}

Can you try giving CmsComponentData in the constructor, check whether it resolves the issue or not

Related

GET() communication between Angular and Node JS

I have an Angular and Node JS project with Typescript in which I am trying to create the communication between them using a service.
When making a get() request from the front I can't get anything from the back, I don't know what I might be missing to configure or what problem I have in the service.
This is the API response:
This is the service.ts:
import { Injectable } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Injectable({
providedIn: 'root'
})
export class DashboardService {
private url = 'http://localhost:8080/list/product'
constructor(
private http: HttpClient
) {}
public getTest() {
return this.http.get(`${this.url}`);
}
}
This is the component.ts where I am trying to display the message on the console:
import { Component, OnInit } from '#angular/core';
import { DashboardService } from './dashboard.service';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
constructor(
private dashboardService: DashboardService
) {
}
ngOnInit() {
console.log('hola')
console.log(this.dashboardService.getTest().subscribe())
}
}
This is what I get on the console:
How should I do the GET() request to communicate with the back?
You are subscribing but then doing nothing with the subscription. I recomment you read up on angular subscriptions a bit more, but effectively what you want to do is get the result from the subscription like so.
items: string[];
this.dashboardService.getTest().subscribe({
next: result => items = result,
});
Also your get method in your service needs a bit of work.
public getTest(): Observable<string[]> {
return this.http.get<string[]>(`${this.url}`);
}
This is for returning a list of strings

React - accessing context in child components

I am using this react package - #spyna/react-store (link) in my project which is nothing but a wrapper for React Context API - createStore & withStore. But I am not able to access the react context api store values in my child component (which I set in the App component).
Actually when I try to access this.props.store.get("amount") I am getting an compilation error saying "props store does not exist". Please advise me on how to access the context in my child component. Thanks in advance.
App component:
import { createStore } from "#spyna/react-store";
class App extends React.Component<IAppProps> {
render() {
<Route component={this.ChildComponent} />
}
private ChildComponent= () => <Child1/>;
}
const initialValue = {
amount: 15,
username: {
name: "spyna",
url: "https://spyna.it"
}
};
export default createStore(App, initialValue);
Child component:
import { withStore } from "#spyna/react-store";
interface ICustomProps {
...
}
interface IAppProps {
...
}
class Child1 extends React.Component<ICustomProps & IAppProps, IAuthState> {
render() {
return (
<p>My Amount: {this.props.store.get('amount')}</p>
)
}
}
export default withStore(Child1)

Angular 4.x component property always null when routing to it [duplicate]

This question already has answers here:
How do I return the response from an Observable/http/async call in angular?
(10 answers)
Closed 5 years ago.
I have the following component:
import { Component, Input, OnInit } from '#angular/core';
import { ActivatedRoute, Params } from '#angular/router';
import 'rxjs/add/operator/switchMap';
import { ArticleStore } from '../../state/ArticleStore';
import { Article } from '../../models/article';
#Component({
selector: 'app-article-detail',
templateUrl: './article-detail.component.html',
styleUrls: ['./article-detail.component.css']
})
export class ArticleDetailComponent implements OnInit {
private article: Article;
constructor( private route: ActivatedRoute, private articleStore: ArticleStore ) { }
ngOnInit(): void {
this.route
.queryParamMap
.map((paramMap => paramMap.get('id') || 'None'))
.switchMap((id: string) => this.articleStore.getArticle(id))
.subscribe((article: Article) => {
this.article = new Article(article);
console.log(this.article) // <--returns full-filled object
});
console.log(this.article) // <-- undefined object
}
}
Inside the subscribe function, I get the proper object (this.article) and is what I expect. If I move down to after the this.route, it doesn't work. Should be straight forward to get the value assigned.
The whole project is here => https://github.com/flamusdiu/micro-blog
Edit
Kinda similar to How do I return the response from an Observable/http/async call in angular2?
I understand the async nature of the calls (actually more calls now-a-days are async).
When you nav to article/:id, it fires off the getArticle(id) function from the ArticleStore.ts
public getArticle (id: string) {
return this.pouchdbService.getArticle(id)
.then((res) => {return res.docs[0] });
}
This runs just fine. It pulls from my service:
public getArticle(id: string): Promise<any> {
return this._pouchDb.find({
selector: {_id: id }
});
}
In your application routes you should have something like:
{ path: '/articles/:id', component: ArticleDetailComponent},
Then your router will be able to act on the provided article route.
Also consider using a Resolver for getting data for the component before it is initialized. good luck with the blog :D

ts2304 cannot find name 'OnInit'

I've worked through the Angular superhero tutorial. It all works.
If i close the cmd window running NPM, then re-open a CMD window and reissue the NPM START command I get two errors
src/app/DashBoard.component.ts(12,44) TS2304 : Cannot find name 'OnInit'.
src/app/hero-list.component.ts(16, 434) TS2304 : Cannot find name 'OnInit'.
I can resolve this by removing
Implements OnInit
from both these classes,
run NPM start
re-add them (simply CTL Z in the editor)
make some change , save.
The app recompiles and I am off and running.
I have 4 classes that implement this function. I have studied them and can not figure out what makes 2 fail...
I have read posts that reference TS2304, but this seems to be a generic Function/Variable/Symbol not found message ...
I don't know what to post. I'm happy to post any of the code.
Is this caused by errors in modules this depends on (hero.ts)?
Here is one class that is failing in this manner.
This is the hero-list.component.ts file
(at various points in the demo/online examples, this is also named Heroes.component..)
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { Hero } from './hero';
import { HeroService } from './hero.service';
#Component({
selector: 'hero-list',
templateUrl: './hero-list.component.html' ,
providers: [HeroService],
styleUrls: [ './hero-list.component.css']
})
export class HeroListComponent implements OnInit {
heroes : Hero[];
selectedHero: Hero;
constructor(
private router : Router ,
private heroService: HeroService
) { }
ngOnInit(): void {
this.getHeroes();
}
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
getHeroes(): void {
this.heroService.getHeroes().then(heroes => this.heroes = heroes);
}
gotoDetail() {
this.router.navigate(['/detail', this.selectedHero.id]);
}
add(name: string): void {
name = name.trim();
if (!name) { return; }
this.heroService.create(name)
.then(hero => {
this.heroes.push(hero);
this.selectedHero = null;
});
}
delete(hero: Hero): void {
this.heroService
.delete(hero.id)
.then(() => {
this.heroes = this.heroes.filter(h => h !== hero);
if (this.selectedHero === hero) { this.selectedHero = null; }
});
}
}
You have to import OnInit.
import { Component, OnInit } from '#angular/core';
The tutorial fails to mention that you need to add the import of OnInit to TypeScript file app.component.ts:
import { Component, OnInit } from '#angular/core';

Angular 2 SimpleChanges Object throws error at first npm start

In my angular 2 application there is a component containing an array of objects that is passing the chosen (clicked) one to it's direct child component. This does display the data more detailed. I'm using the "SimpleChanges" feature to watch in this child component if the object given changed to make another http request to get the related comments from a database.
If I try to build it with npm I get an error, saying :
app/displayEntry.component.ts(23,41): error TS2339: Property 'entry' does not exist on type 'SimpleChanges'
If I just comment this part out, start npm and finally put it in there again and save it, there is no Problem anymore ( no erro and it works ).
My question is, is there a way to work around this behavior and can this cause any trouble later I don't foresee or should I just ignore it? Thanks for your help
Parent component:
import { Component, OnInit } from '#angular/core';
import { entry } from './Objekte/entry';
import { entryService } from './entry.service'
#Component({
templateUrl: 'app/Html_Templates/displayLastEntrys.template.html'
})
export class displayLastEntrys implements OnInit{
public entrys : entry[];
private entryChoosen: boolean;
private ChoosenEntry : entry;
constructor ( private entryservice : entryService){
this.entryChoosen = false;
}
ngOnInit() : void {
this.getData();
}
getData() {
this.entryservice.getFirstEntrys().then(entrys => this.entrys = entrys);
}
entryClicked(ent: entry){
this.entryChoosen = true;
this.ChoosenEntry = ent;
}
leaveEntry () {
this.entryChoosen = false;
}
voted( upordown : boolean ) {
}
}
Child component:
import { Component, Input, Injectable, OnChanges , SimpleChanges, Output, EventEmitter} from '#angular/core';
import { entry} from './Objekte/entry';
import { entryService } from './entry.service';
import { comment } from './Objekte/comments';
#Component({
selector: 'display-entry',
templateUrl: 'app/Html_Templates/displayEntry.template.html'
})
export class displayComponent implements OnChanges{
#Input() public entry : entry;
public comments : comment[];
private changecounter : number;
constructor(private service : entryService) {
this.changecounter = 0;
}
ngOnChanges(changes : SimpleChanges){
this.service.getComments(changes.entry.currentValue.id)
.then(com => this.comments = com )
.catch();
this.entry.viewed++;
// To implement :: change database
}
votedUp () : void {
this.entry.votes ++;
// To implement :: change database
}
votedDown () : void {
this.entry.votes --;
// To implement :: change database
}
}
The accepted solution is suboptimal for TypeScript, as you're defeating the type system.
SimpleChanges does not have an entry property, so the compiler quite rightly balks. The solution is to treat the changes object as an array:
ngOnChanges(changes : SimpleChanges){
if (changes['entry']) {
this.service.getComments(changes['entry'].currentValue.id)
}
}
Then you can continue to strongly type the ngOnChanges method.
To make the compiler not complain just change your method definition for parameter one from SimpleChanges to any:
ngOnChanges(changes: any) {
//...
Maybe it's changed a lot now but this works these days
import {Component, Input, OnChanges, SimpleChanges} from '#angular/core';
import {ConfigModel} from './config.model'
#Component({
selector: 'selector',
templateUrl: './template.html',
styleUrls: ['./styles.scss']
})
export class BlaComponent implements OnChanges {
#Input() config: ConfigModel;
ngOnChanges(changes: SimpleChanges): void {
if (changes.config && changes.config.currentValue) {
let config = <ConfigModel>changes.config.currentValue;
// do more
}
}
}
I myself got the compile error because i wasn't using .currentValue after calling changes.config
If you are completely dependent on the IDE's auto-completion, make sure to actually use SimpleChanges instead of just SimpleChange. A very thing to be overlooked at.

Resources