Angular2 : Bind view with callback variable - javascript

In my angular2 project, I read a csv file with FileReader. After the onloadend callback I have a variable which contain the content of my csv file.
Here my component.ts :
items: Array<any> = []
...
readCSV (event) {
let csvFileParseLog = this.csvFileParseLog;
r.onloadend = function(loadedEvt) {
devicesFile = files[0];
let csvFileParseLog = [];
parseDevicesCsvFile(contents) // One of my function which is an observable
.subscribe(newItems=> {
csvFileParseLog.push(newItems); // My result
},
exception => { ... }
);
};
}
I tried to bindcsvFileParseLog to my view by passing my value into items ... whithout success.
Here my componenet.html :
<div *ngFor="let c of csvFileParseLog">
{{ c.value }}
</div>
How can I display this content into my view component and loop on it with ngFor ?

r.onloadend = function(loadedEvt) {
should be
r.onloadend = (loadedEvt) => {
otherwise this won't work within that function.
and then just use
this.csvFileParseLog.push(newItems);
and just drop let csvFileParseLog = this.csvFileParseLog;
You also might need to inject
constructor(private cdRef:ChangeDetectorRef) {}
and call it in subscribe()
.subscribe(newItems=> {
this.csvFileParseLog.push(newItems);
this.cdRef.detectChanges();
},

Related

dynamic variable using name reference

I would like to create generic functionality for my extension of react-table where i can pass custom components with custom properties to it.
I have JSON that have structure like this:
[
{
"Header": "stg",
"accessor": "accessor",
"customComponent": "customComponent",
"props": { "functions":
["functionInProp"],
"data":
["prop"]
}
}
]
Logic behind this should be:
this.customCell = (cell, customComponent, customProps) => {
// create props to pass to customComponent
const propsToPass = {};
if (customProps && customProps.functions) {
customProps.functions.forEach(fnc => { propsToPass[fnc] = this[fnc]; });
}
if (customProps && customProps.data) {
customProps.data.forEach(data => { propsToPass[data] = data; });
}
/* eslint-disable import/no-dynamic-require */
const ComponentToRender = require(`${EXTENSIONS_PATH}${customComponent}`).default;
/* eslint-enable import/no-dynamic-require */
return <ComponentToRender cell={cell} {...propsToPass} />;
};
where customComponent and customProps are from JSON. Component is loaded correctly. function is passed within props ok - function in parent component is defined in upper scope like :
this.functionInProp = () => {}
But i dont know how to pass value from variable somewhere named as "prop" within props. This line:
if (customProps && customProps.data) {
customProps.data.forEach(data => { propsToPass[data] = data; });
}
I just need to pass 'data' as "name reference" of variable, not its value.
Can anybody help? Thanks

unable to select all checkboxes in tree using angular2-tree on init

Objective : i have a button named "feed data" so when ever i click it the data will be loaded i mean the tree with checkboxes here my requirement is when ever i click it along with data all the check boxes have to be checked on init i tried using
this.treeComp.treeModel.doForAll((node: TreeNode) => node.setIsSelected(true));
but it is not working below is my code
click(tree: TreeModel) {
this.arrayData = [];
let result: any = {};
let rs = [];
console.log(tree.selectedLeafNodeIds);
Object.keys(tree.selectedLeafNodeIds).forEach(x => {
let node: TreeNode = tree.getNodeById(x);
// console.log(node);
if (node.isSelected) {
if (node.parent.data.name) //if the node has parent
{
rs.push(node.parent.data.name + '.' + node.data.name);
if (!result[node.parent.data.name]) //If the parent is not in the object
result[node.parent.data.name] = {} //create
result[node.parent.data.name][node.data.name] = true;
}
else {
if (!result[node.data.name]) //If the node is not in the object
result[node.data.name] = {} //create
rs.push(node.data.name);
}
}
})
this.arrayData = rs;
tree.selectedLeafNodeIds = {};
}
selectAllNodes() {
this.treeComp.treeModel.doForAll((node: TreeNode) => node.setIsSelected(true));
// firstNode.setIsSelected(true);
}
onTreeLoad(){
console.log('tree');
}
feedData() {
const results = Object.keys(this.data.info).map(k => ({
name: k,
children: this.data.info[k].properties
? Object.keys(this.data.info[k].properties).map(kk => ({ name: kk }))
: []
}));
this.nodes = results;
}
feedAnother() {
const results = Object.keys(this.dataa.info).map(k => ({
name: k,
children: this.dataa.info[k].properties
? Object.keys(this.dataa.info[k].properties).map(kk => ({ name: kk }))
: []
}));
this.nodes = results;
}
onActivate(event) {
this.selectedDataList.push(event.node.data);
console.log(this.selectedDataList)
}
onDeactivate(event) {
const index = this.selectedDataList.indexOf(event.node.data);
this.selectedDataList.splice(index, 1);
console.log(this.selectedDataList)
}
below is my stackblitz https://stackblitz.com/edit/angular-hrbppy
Use updatedata and initialized event to update the tree view to check all checkboxes.
app.component.html
<tree-root #tree *ngIf ="nodes" [nodes]="nodes" [options]="options" [focused]="true"
(initialized)="onTreeLoad()"
(updateData)="updateData()"
(select)="onActivate($event)"
(deselect)="onDeactivate($event)">
</tree-root>
It'll initiate tree-root component only if nodes variable is available,
then in the initialized and updateData event call selectAllNodes method to select all checkboxes.
app.component.ts
updateData() {
this.selectAllNodes();
}
onTreeLoad(){
this.selectAllNodes();
}
Refer to this slackblitz for working example.
just, in your function feed data call to your function this.selectAllNodes() enclosed in a setTimeout. You can see your forked stackblitz
setTimeout(()=>{
this.selectAllNodes()
})
NOTE: I see in your code you try to control in diferents ways the items selected. I simplified using a recursive function.
In this.treeComp.treeModel.selectedLeafNodeIds we have the items that are changed, so
getAllChecked()
{
const itemsChecked=this.getData(
this.treeComp.treeModel.selectedLeafNodeIds,null)
console.log(itemsChecked);
}
getData(nodesChanged,nodes) {
nodes=nodes||this.treeComp.treeModel.nodes
let data: any[] = []
nodes.forEach((node: any) => {
//in nodesChanged we has object like {1200002:true,123132321:false...}
if (nodesChanged[node.id]) //can be not changed, and then it's null because
//it's not in object or can be changed to false
data.push({id:node.id,name:node.name})
//or data.push(node.name); //if only need the "name"
if (node.children)
data=[...data,...this.getData(nodesChanged,node.children)]
}
);
return data
}
Updated I updated the function getData to include the "parent" of the node, but looking the code of #Raghul selvam, his function like me more than mine.
getData(nodesChanged,nodes,prefix) {
nodes=nodes||this.treeComp.treeModel.nodes
let data: any[] = []
nodes.forEach((node: any) => {
if (nodesChanged[node.id])
data.push(prefix?prefix+"."+node.name:node.name)
if (node.children)
data=[...data,...this.getData(nodesChanged,node.children,prefix?prefix+"."+node.name:node.name)]
}
);
return data
}
And call it as
this.getData(this.treeComp.treeModel.selectedLeafNodeIds,null,"")
You could add this in your onTreeLoad function. You could add a boolean flag(treeLoaded) for tracking if the tree has loaded or not.
onTreeLoad(tree){
this.selectAllNodes();
this.treeLoaded = true;
}

TypeScript myFunction is not a function

I am working in Angular and I have a following situation:
my.service.ts has this class:
export class MyClass {
MyList: string[] = [];
MyString: string = '';
createString(): void {
this.MyList.forEach(s => {
this.MyString += s + ', ';
});
}
}
And my.component.ts calls it like this:
myData: MyClass[] = [];
this.myService.getMyData().subscribe(res => {
myData = res;
if (myData.length > 0) {
this.myData.forEach(x => x.createString());
}
});
VS Code recognizes the createString function as a metod of MyClass, but I still get an error:
ERROR TypeError: x.createString is not a function
Any explanations?
EDIT: The data comes from back end, and the back end model doesn't have this method. Maybe that is the issue?
The object coming from the server will be just a simple object not an instance of the class MyClass. You can create instances of MyClass and assign the values from the server object to the instance of the class:
this.myService.getMyData().subscribe(res => {
myData = res.map(o => Object.assign(new MyClass(), o));
if (myData.length > 0) {
this.myData.forEach(x => x.createString());
}
});
Accepted soulution didn't help me, so I propose mine. It does not require .map().
My http service:
getOffers() {
return this.http.get('https://ohipo.pl/assets/oferty.json');
}
Consuming service in component:
offers: Offer[] = [];
this.offersService.getOffers().subscribe((response: Offer[]) => {
for (let i in response) {
this.offers[i] = Object.assign(new Offer(), response[i]);
}

Ngrx selector not triggering updates

My state is :
export interface RequestState {
tabsContent: TabContent[];
}
Where TabContent represent an array of visual tabs containing 1 Request each and additionnal infos :
export interface TabContent {
tabInfo: TabInfo;
request: Request;
results?: any[];
}
I have this specialized selector to get one Request from a single TabContent :
export const getRequestForTabInfo = (tabInfo: TabInfo) => createSelector(
getTabContent,
(tabContent: TabContent[]) => {
const tabContentFiltered = tabContent.filter(tab =>
tab.tabInfo.id === tabInfo.id
&& tab.tabInfo.index === tabInfo.index
&& tab.tabInfo.state === tabInfo.state);
if (tabContentFiltered && tabContentFiltered.length === 1) {
return tabContentFiltered[0].request;
}
return {} as Request;
},
);
and this basic one to get all TabsContent :
export const getTabContent = createSelector(
getRequestFeatureState,
state => state.tabsContent,
);
based on this FeatureSelector :
const getRequestFeatureState = createFeatureSelector<RequestState>('requests');
Defined in a facade service :
tabsContent$: Observable<TabContent[]>;
constructor(private store: Store<fromRequest.State>) {
this.tabsContent$ = this.store.pipe(
select(fromRequest.getTabContent),
takeUntil(this.componentDestroy()),
);
}
public getRequest(tabInfo: TabInfo): Observable<Request> {
return this.store.pipe(
select(fromRequest.getRequestForTabInfo(tabInfo)),
takeUntil(this.componentDestroy()),
);
}
and used in the component :
private initializeComponent(): void {
this.requestFacade.getRequest(this.tabInfo).pipe(
takeUntil(this.componentDestroy()),
).subscribe(request => {
console.log('request : ', request);
this.request = request;
});
this.requestFacade.tabsContent$.pipe(
takeUntil(this.componentDestroy()),
).subscribe(tab => {
console.log('tab : ', tab);
});
}
When the component is consctructed I get both logs, but when I update part of the related state (I update the content of one Request) only the tab log appear.
Why is the filtered selector observable not doing anything ?
You're using a static parameter in the getRequestForTabInfo selector so it presumes that it will not change overtime, which is why you are not getting the changes.
Instead of passing in parameters, I would suggest dispatching an action to set the selected tabinfo in the store and use selectors to retrieve it. You already have TabContents in store so should be able to reuse some of the logic you've already have.

Get the value of a local variable into the controller in AngularJS

I have a JS file containing a controller and other functions structured like this:
class RandomCtrl {
constructor(randomService) {
this.randomService = randomService;
...
}
$onInit() {
getData.call(null, this);
}
...
}
function getData(RandomCtrl) {
...
}
function getChart(data) {
if (!data) {
return;
}
const chartOptions = getWeekHourlyOptions(data);
const allCols = [].concat(chartOptions.dataColumns);
allCols.push(["x"].concat(_.map(chartOptions.xAxis, element => moment(element).valueOf())));
const xVals = xAxisValues(chartOptions.xAxis);
...
}
...
RandomCtrl.$inject = ['randomService'];
export const Random = {
bindings: {
data: '<',
siteNames: '<'
},
templateUrl: randomPageHtml,
controller: RandomCtrl
};
I want to get the value of allCols from getChart() into the Controller.
I've tried to add it in $onInit like this.allCols = getData.allCols but it doesn't work. Probably not the right way.
Any solution to this?
Declare allCols as a global variable and populate the data in getChart()
send allCols in getChart() as return value so that whenever this method is called the return value can be stored into another variable and can be consumed

Categories