Angular2 Sorting Pipe with Object Array - sorting

How to make a sorting pipe in angular2 with an array of objects
Original Problem:
I have a TODOs list, (Todo[ ]) and I want to sort it every time I make some changes. I want that the completed todo are displayed at the bottom of the list. The Todo object has a property named .completed that stores a boolean value, it will tell us if the todo is completed or not.
Creating the Pipe:
In Angular2 the "OrderBy" pipe does not exist. So we have to build it:
import { Pipe, PipeTransform } from "angular2/core";
//Todo is the interface for our todo object
import {Todo} from './todo';
#Pipe({
name: "sort",
//set to false so it will always update, read below the code.
pure: false
})
export class TodosSortPipe implements PipeTransform {
transform(array: Todo[], args: any): Todo[] {
//watch the console to see how many times you pipe is called
console.log("calling pipe");
/* javascript is async, so could be that the pipe is called before
that the todos list is created, in this case we do nothing
returning the array as it is */
if (isBlank(array)) return null;
array.sort((a, b) => {
if (a.completed < b.completed) {
return -1;
//.completed because we want to sort the list by completed property
} else if (a.completed > b.completed) {
return 1;
} else {
return 0;
}
});
return array;
}
}
If you didn't understand the sort method check MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
The Pipe is done, let's move to the Component.
Creating the Component:
The AppComponent class, creates an array of Todo, called Todos, getting the objects from a mock with a service.
import {Component, OnInit} from 'angular2/core';
import {Todo} from './todo';
import {TodoService} from './todo.service';
import {TodosSortPipe} from './sort-pipe.component'
#Component({
//name of the html element
selector: 'my-app',
//view of the selector, " ` " is alt + 9
templateUrl: "./app/todo-list.component.html",
providers: [TodoService],
pipes: [ TodosSortPipe ]
})
export class AppComponent implements OnInit{
public todos: Todo[];
public edited = false;
public changes = 0;
//creating an istance of todoService
constructor(private _todoService: TodoService) { };
//getting the todos list from the service
getTodos() {
this._todoService.getTodos().then(todos => this.todos = todos);
}
(...)
editTodo(todo: Todo): void {
//slice is very important, read below the code
this.todos = this.todos.slice();
this.saveTodos();
}
}
Template implementation
This is the pipe calling:
<li *ngFor="#todo of todos | sort; #i=index">
(...)
</li>
Demo:
For the full example with all the code: https://plnkr.co/edit/VICRMVNhqdqK9V4rJZYm?p=preview
Watch it on github: https://github.com/AndreaMiotto/Angular2-TodoApp
Pipe Unpure
Pipes only change by default when your Pipe input parameters change and not when your data changes.
Setting Pure to false, you will make it "unpure" so you pipe will always update.

Perhaps the value todos is null at the beginning because it's loaded asynchronously using HTTP.
To prevent from such use case you could add this in your pipe:
#Pipe({
name: "sort"
})
export class TodosSortPipe implements PipeTransform {
transform(array: Todo[], args: any): Todo[] {
if (array == null) {
return null;
}
(...)
}
}
Then the value todos will be received and the transform method of the pipe will be called again with this non null value...
Moreover it seems that your <li> tag isn't ended. You must have valid HTML into component templates. I don't know if it's the complete code or a truncated one...
Hope it helps you,
Thierry

I've created an OrderBy pipe that supports both single and multi-dimensional arrays. It also supports being able to sort on multiple columns of the multi-dimensional array.
<li *ngFor="#todo of todos | orderBy : ['completed']; #i=index">
{{i}}) {{todo.name}} - {{todo.completed}}
</li>
This pipe does allow for adding more items to the array after rendering the page, and still sort the arrays with the new items dynamically.
I have a write up on the process here.
And here's a working demo: http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby and https://plnkr.co/edit/DHLVc0?p=info

You need to change your html template so that your pipe can accommodate your async code.
Change this line:
<li *ngFor="#todo of todos | sort; #i=index">
(...)
</li>
To this:
<li *ngFor="#todo of todos | async | sort; #i=index">
(...)
</li>
I copied your Pipe code into this Plunker:
https://plnkr.co/edit/RBpZilgxIyRDLwktNZN1?p=preview

Related

check store for object before calling api

You know how they say you don't need state management until you know you need it. Well turns out my project needs it. So I need some help wit best practice as I am adding ngxs to an existing angular project.
I have an action called getServiceDetail and my statemodel has a list of objects called DriverListsStopInfoViewModel. each of these objects have a unique ID. The html template of the consuming component uses a selector for the property currentStopDetail, which is a state property that gets set in my action.
GOAL:
in my action I want to check the list of objects in my store to see if an object with the same id exists and return that object, and if it does not exist, call and api to get it.
EXAMPLE:
The following code works, but I would like to hear if this is the right way to do it. do I even need to return the object from the action function if its found, or can I just use patch state to assign it to the currentStopDetail
export interface SignServiceStateModel {
searchResults: ServiceSearchModel[];
driverStopsDetails: DriverListsStopInfoViewModel[];
driverStopsList: DriverListsStopsViewModel[];
driverStopsMarkers: DriverStopsMarkerViewModel[];
currentStopDetail: DriverListsStopInfoViewModel;
}
const SIGNSERVICE_STATE_TOKEN = new StateToken<SignServiceStateModel>(
'signservice'
);
#State<SignServiceStateModel>({
name: SIGNSERVICE_STATE_TOKEN,
defaults: {
searchResults: [],
driverStopsDetails: [],
driverStopsList: [],
driverStopsMarkers: [],
currentStopDetail: null
},
})
#Injectable()
export class SignServiceState {
constructor(private driverListsService: DriverListsService) {}
#Action(DriverList.GetServiceDetail)
getServiceDetail(
ctx: StateContext<SignServiceStateModel>,
action: DriverList.GetServiceDetail
) {
if (action.serviceId === undefined || action.serviceId <= 0) {
return;
}
// check if record already in list and return
const currentState = ctx.getState();
const existingStopDetail = currentState.driverStopsDetails.find(s => s.SignServiceId === action.serviceId);
if (existingStopDetail !== undefined) {
const currentStopDetail = existingStopDetail;
ctx.patchState({ currentStopDetail });
return currentStopDetail;
}
// else get new record, add it to list and return
return this.driverListsService.getDriverListsInfo(action.serviceId).pipe(
tap((currentStopDetail) => {
ctx.patchState({ currentStopDetail });
ctx.setState(
patch({
driverStopsDetails: append([currentStopDetail])
})
);
})
);
}
#Selector()
static currentStopDetail(state: SignServiceStateModel) {
return state.currentStopDetail;
}
}
I only included the relevant code from my state class
QUESTION:
is this the best way to check the store for an item and call api if it does not exist?
Thanks in advance
Short answer is yes, what you have done here is a typical way of handling this scenario (in my experience). There's a couple of improvements you could make:
do I even need to return the object from the action function if its found, or can I just use patch state to assign it to the currentStopDetail
No, you don't return anything from these action handlers, other than possibly an Observable that NGXS will handle (so in your case if there is no matching item found, you return the Observable that fetchs it from the API and patches the state).
Also when you do make the API call, you should only need a single update to the state:
return this.driverListsService.getDriverListsInfo(action.serviceId).pipe(
tap((result) => {
ctx.setState(
patch({
currentStopDetails: result
driverStopsDetails: append([result]),
})
);
})
);

How to create custom floating filter component in ag-grid that uses "inRange" filter type

I'm trying to build a custom filter component that takes a range from a text input control (e.g. '3-5') to filter the data. To do so I have modified the example given in the ag-grid documentation (see code below).
When changing the type in onFloatingFilterChanged() to 'equals', 'greaterThan', 'lessThan' etc. everything works fine. But with type 'inRange' no filtering is performed.
Working example can be found on Plunkr: https://plnkr.co/edit/oHWFIaHgWIDXP0P5
import { Component } from '#angular/core';
import {
IFloatingFilter,
IFloatingFilterParams,
NumberFilter,
NumberFilterModel,
} from '#ag-grid-community/all-modules';
import { AgFrameworkComponent } from '#ag-grid-community/angular';
export interface RangeFloatingFilterParams extends IFloatingFilterParams {
value: number;
}
#Component({
template: `
<input
type="text"
[(ngModel)]="currentValue"
(ngModelChange)="valueChanged()"
style="width: 70px;"
/>
`,
})
export class RangeFloatingFilter
implements IFloatingFilter, AgFrameworkComponent<RangeFloatingFilterParams> {
private params: RangeFloatingFilterParams;
public currentValue: string;
agInit(params: RangeFloatingFilterParams): void {
this.params = params;
this.currentValue = '';
}
valueChanged() {
let valueToUse = this.currentValue === 0 ? null : this.currentValue;
this.params.parentFilterInstance(function(instance) {
(<NumberFilter>instance).onFloatingFilterChanged(
'inRange',
valueToUse
);
});
}
onParentModelChanged(parentModel: NumberFilterModel): void {
if (!parentModel) {
this.currentValue = 0;
} else {
// note that the filter could be anything here, but our purposes we're assuming a greater than filter only,
// so just read off the value and use that
this.currentValue = parentModel.filter;
}
}
}
Faced the same issue with custom floating datepicker. I used setModelIntoUi method instead of onFloatingFilterChanged:
instance.setModelIntoUi({
type: 'inRange',
dateFrom: moment(value.min).format('YYYY-MM-DD'), // you have to use exactly this date format in order for it to work
dateTo: moment(value.max).format('YYYY-MM-DD'),
});
And in your case with numbers it'll be:
instance.setModelIntoUi({
type: 'inRange',
filter: value.min,
filterTo: value.max,
});
UPD: Added this line
instance.onUiChanged(true);
after the setModelIntoUi method, because of the bug: filter model wasn't updating on second use.
The code inside instance.onFloatingFilterChanged() only sets the first from value.
Use these lines below to get the correct result, as it is the only way to get inRange working.
instance.setTypeFromFloatingFilter('inRange');
instance.eValueFrom1.setValue(this._input1.value);
instance.eValueTo1.setValue(this._input2.value);
instance.onUiChanged(true);

RxJS Filtering and selecting/deselecting list of checkbox

I have a list of checkboxes, and I need to be able to select them ( check them) and I should also be able to filter them and check them while they are filtered. I am able to select the item, filter the item, but as soon as I filter them and then check any value it unchecks the previously selected value. I know the reason why it unchecks because every time user checks/unchecks the value I start with the original checkbox value set. So when I check/uncheck a value in filtered set, it starts again with default set where checkbox value is set to false.
Any suggestions on how to make it work? That is works seamlessly with filtering and checking/unchecking the values.
It looks like a really simple issue but i am stuck with it from past few days. Replicated the issue here. Please take a look. Any suggestions are appreciated .
https://stackblitz.com/edit/angular-wmyxtd
variables = [
{
"label": "Phone",
"value": "phone",
checked: false
},
{
"label": "Machine Id",
"value": "machine_id",
checked: false
},
{
"label": "Address",
"value": "address",
checked: false
},
{
"label": "Store",
"value": "store",
checked: false
},
{
"label": "Email",
"value": "email",
checked: false
},
{
"label": "Name",
"value": "name",
checked: false
},
{
"label": "Credit Card",
"value": "credit_Card",
checked: false
},
{
"label": "Bank Account",
"value": "bank_account",
checked: false
}
]
variables$ = of(this.variables).pipe(shareReplay(1),delay(1000));
filteredFlexibleVariables$ = combineLatest(this.variables$, this.filterBy$).pipe(
map(([variables, filterBy]) => {
return variables.filter((item) => item.value.indexOf(filterBy) !== -1);
})
);
toggleStateSelectedVariables$ = combineLatest(
this.variables$,
this.toggleFlexibleVariableBy$
).pipe(
map(([availableVariables, clickedVariable]) => {
const clickedVariableValues = clickedVariable.map((item) => item.value);
if (clickedVariable.length) {
// If condition just to save availableVariables iteration for no reason if there is no clicked variables
return availableVariables.map((variable) => {
const checked = clickedVariableValues.indexOf(variable.value) !== -1;
return {
...variable,
checked
};
});
}
return availableVariables;
}),
);
flexibleVariables$ = merge(
this.filteredFlexibleVariables$,
this.toggleStateSelectedVariables$
);
I'd take a different approach. As you're trying to edit a group of values, this makes me think that using a form would be a good idea.
I'm one of the authors of ngx-sub-form and I'll explain the approach I would take using this library to (hopefully?) simplify the workflow and encapsulate the edition of the data then just be warned whenever the form value changes.
Before we start, here's a stackblitz you can play with to see my solution:
https://stackblitz.com/edit/angular-nhnmcm
First, I'd like to point out that the filter should not be tight to the data themselves. It should just show or hide data in the view based on the filter. For that, we can use a pipe:
filter-item.pipe.ts
#Pipe({
name: "filterItem"
})
export class FilterItemPipe implements PipeTransform {
public transform(item: Item, searchFilter: string): Item {
return item.value.includes(searchFilter);
}
}
And before I forget, here's what an "Item" looks like:
export interface Item {
label: string;
value: string;
checked: boolean;
}
Now, within our main component we don't want to be aware of how the data are being displayed nor visualized. The only thing which matters is:
Where do we get our data from?
When do we update them?
app.component.ts
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
public items$: Observable<Item[]> = this.itemsService.items$;
public search: string = "";
constructor(private itemsService: ItemsService) {}
public itemsUpdated(items) {
this.itemsService.updateItems(items);
}
}
Then, from the view of the main component, we should have 2 components:
One to tell us what's the value of the filter
One to display the list of items and tell us when it's been updated
app.component.html
<app-items-filter (search)="search = $event"></app-items-filter>
<app-items-form
[items]="items$ | async"
(itemsUpdated)="itemsUpdated($event)"
[searchFilter]="search"
></app-items-form>
So far, it doesn't look too bad, does it?
But how should we build the app-items-form which seems to be holding all the magic?
items-form.component.ts
interface ItemsForm {
items: Item[];
}
#Component({
selector: "app-items-form",
templateUrl: "./items-form.component.html",
styleUrls: ["./items-form.component.css"]
})
export class ItemsFormComponent extends NgxAutomaticRootFormComponent<
Item[],
ItemsForm
> {
#DataInput()
#Input("items")
public dataInput: Item | null | undefined;
#Output("itemsUpdated")
public dataOutput: EventEmitter<Item> = new EventEmitter();
#Input()
searchFilter: string;
protected getFormControls(): Controls<ItemsForm> {
return {
items: new FormArray([])
};
}
protected transformToFormGroup(obj: Item[]): ItemsForm {
return {
items: obj
};
}
public getDefaultValues(): Partial<ItemsForm> {
return {
items: []
};
}
protected transformFromFormGroup(formValue: ItemsForm): Item[] | null {
return formValue.items;
}
}
It may look like a lot is going on there if you haven't discovered ngx-sub-form yet. So let me walk you through it.
We use a top level class called NgxAutomaticRootFormComponent. That class will ask us to implement the form which is going to hold our data and will automagically bind the form to our input and give us the updated value as an output every time the form is being updated.
It might be slightly easier but as it's an array we need to wrap the array into an object as ngx-sub-form only wants to deal with a FormGroup internally. But that formGroup can contain a FormArray (which is what we just did there).
Now, let's take a look to the view:
items-form.component.html
<ng-container [formGroup]="formGroup">
<ng-container [formArrayName]="formControlNames.items">
<app-item-ctrl [hidden]="!(itemCtrl.value | filterItem:searchFilter)"
*ngFor="let itemCtrl of formGroupControls.items.controls" [formControl]="itemCtrl">
</app-item-ctrl>
</ng-container>
</ng-container>
Few important things to notice:
- ngx-sub-form gives us access to a formGroup property that we can use directly without having to declare it ourselves
- as we're holding a list of values, we use the formArrayName directive to work with the FormArray
- we use the hidden directive provided natively by Angular to hide the controls which are not included by our filter
- last, we delegate the display/edit of the item to a sub component called app-item-ctrl
This is the "magic" part of ngx-sub-form. It's really easy to break down a form into sub form and also at the top level abstract how it's been displayed/edited.
Final part, let's take a look into the sub component:
item-ctrl.component.ts
#Component({
selector: "app-item-ctrl",
templateUrl: "./item-ctrl.component.html",
styleUrls: ["./item-ctrl.component.css"],
providers: subformComponentProviders(ItemCtrlComponent)
})
export class ItemCtrlComponent extends NgxSubFormComponent<Item> {
protected getFormControls(): Controls<Item> {
return {
label: new FormControl(),
value: new FormControl(),
checked: new FormControl()
};
}
}
Things to notice:
providers: subformComponentProviders(ItemCtrlComponent): behind the scenes, ngx-sub-form is a simple wrapper to deal with a ControlValueAccessor in an easier way and with a lot less boilerplate. Hence, we need to register the DI tokens required by a ControlValueAccessor through that simple function where you just pass the class of the current component
getFormControls this is the method where we have to pass an object that'll be used to create our internal formGroup
And the corresponding view:
item-ctrl.component.html
<div [formGroup]="formGroup">
{{ formGroupValues.label }}
<input type="checkbox" [formControl]="formGroupControls.checked" />
</div>
Conclusion:
When you need to edit data, I'd recommend using a form. Whether you use ngx-sub-form or decide to use forms directly is up to you.
If I'm explaining how to use ngx-sub-form though, it's because we've invested quite a lot of time at work to come up with that library as we do manage a lot of forms and we needed to abstract the complexity somehow. It has greatly simplified our workflow and I believe the solution above is quite verbose (by the number of components used) but really simple too as we haven't had to deal with streams for ex. (Even though I do love streams but I don't think that in that case it's the best approach).
Hope it helps and here's the final stackblitz I've made: https://stackblitz.com/edit/angular-nhnmcm
Wow.. so after a lot of brainstorming and frustrating moments I was able to solve this. I was thinking it in a different way. What I ended up doing was to create a stream of toggled Values (select/unselect checkboxes) and then filter on those toggled values.
So in summary -
Stream 1 - Merged stream of original set of variables & clicked variable. Use scan operator to get the updated stream at any point
Stream 2 - Consume the above stream and apply filter on the above stream.
toggleStateSelectedVariables$ = merge(this.variables$, this.toggleFlexibleVariableBy$).pipe(
throttleTime(100),
scan((availableVariables: NzCheckBoxOptionInterface[], clickedVariableValue: NzCheckBoxOptionInterface) => {
return availableVariables.map((variable) => {
// If its clicked, toggle it. If its selected, make it unselected. If unselected, select it
const checked = variable.value === clickedVariableValue.value ? !variable.checked : variable.checked;
return {
...variable,
checked
};
});
}),
);
flexibleVariables$ = combineLatest(this.toggleStateSelectedVariables$, this.filterBy$).pipe(
map(([variables, filterBy]) => variables.filter((item) => item.value.indexOf(filterBy) !== -1);
));
Implementation available here - https://stackblitz.com/edit/angular-ymft6o
Hope this helps someone. If anyone has any better solutions, please chime in
Happy Learning,
Vatsal

Ordered list of redux-form fields

Do you know how can I get the ordered list of field names from given form? Instance API has a property called "fieldList" and it's an array but it's not in correct order. (ordered list = [firstFieldName, secondFieldName, ...] so what I need is a list of field names in order they appear in my form - top to bottom)
Also the redux-form' action '##redux-form/REGISTER_FIELD' is dispatching out of correct form order so I guess it's not what I need here...
(My redux-form version: 7.3.0)
I have experience with redux-form and also have checked its API, but didn't find a documented way for getting the fields in the way they appear in the form.
However, here's how I would do it:
I'll create a Reducer, that will keep track of the fields in the order,
they are registered (appear in the form).
We have very detailed action. As you already mentioned - ##redux-form/REGISTER_FIELD action is dispatching out all the fields in process of being registered in the correct order. This action has the following payload:
{
type: '##redux-form/REGISTER_FIELD',
meta: {
form: 'user'
},
payload: {
name: 'firstName',
type: 'Field'
}
}
Create a reducer. So I'll just create a Reducer, that will listen for all ##redux-form/REGISTER_FIELD actions. Something like that:
// The reducer will keep track of all fields in the order they are registered by a form.
// For example: `user` form has two registered fields `firstName, lastName`:
// { user: ['firstName', 'lastName'] }
const formEnhancedReducer = (state = {}, action) {
switch (action.type) {
case '##redux-form/REGISTER_FIELD':
const form = action.meta.form
const field = action.payload.name
return { ...state, [form]: [...state[form], field] }
default:
return state
}
}
Usage. In order to get ordered fields by a form, you just have access the Store (state) formEnhancer property with the form name: state.formEnhanced.user.
Keep in mind that you have to consider some cases as ##redux-form/DESTROY, but I think it's a pretty straightforward implementation.
I would prefer to keep things simple and just subscribed to ##redux-form/REGISTER_FIELD and just change the reducer implementation a little bit, in order to prevent form fields duplication. So I will just validate if the form field is already registered and won't care for supporting ##redux-form/DESTROY.
Hope it helps.
One way that I have been able to retrieve an ordered list of form field names from a given form is via the registered fields stored in the redux form state using the connect HOC (Higher Order Component) from 'react-redux':
import React, { Component } from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';
class Foo extends Component {
render() {
const {
registeredFields,
} = this.props;
...
...
...
}
}
const mapStateToProps = (state, props) => {
// retrieve the registered fields from the form that is stored in redux state; using lodash 'get' function
const registeredFields = _.get(state, 'form.nameOfYourForm.registeredFields');
// creating an object with the field name as the key and the position as the value
const registeredFieldPositions = _.chain(registeredFields).keys().reduce((registeredFieldPositions, key, index) => {
registeredFieldPositions[key] = index;
return registeredFieldPositions;
}, {}).value();
return({
registeredFieldPositions,
});
};
// registeredFieldPositions will now be passed as a prop to Foo
export default connect(mapStateToProps)(Foo);

Ajax call in MobX: MobX observer: Store is not available! Make sure it is provided by some Provider

I'm migrating from a traditional React application with the tree-structure to a state management structure with MobX.
Currently, my individual components propagate down data from an Ajax call made by the parent/grandparent, which works fine.
Now I wish to change this so that I don't work in the tree structure anymore due to the change of complexity and dependency of parallel grandchildren/children.
Say I do an axios.get in componentDidMount of a <Parent1/> React class. How do I then access the data using MobX?
What I've tried so far:
Creating a store.jsx that looks as such:
import { observable } from 'mobx';
const axios = require('axios');
class Store {
#observable parentdata;
loadParent = () => {
let that = this;
axios.get("/api/parent").then(function(response){
that.parentdata = response.parentdata;
}).catch(function(error){
// Error handling
})
};
}
export default Store;
My ReactDOM is rendered in container.jsx which contains all parents, meaning also <Parent1/>. In container.jsx we do the following:
import { Provider } from 'mobx-react';
import Store from './store/store.jsx';
let store = new Store();
and
ReactDOM.render(
<Provider store={store}>
<Main />
</Provider>,
document.getElementById('content')
);
.. in the end.
In the render method of container.jsx I don't do anything with <Parent1/> - it simply renders the component as normal(that's the idea here, right?)
In parent1.jsx, I remove the previous axios.get and add these:
import { inject, observer } from 'mobx-react';
#inject('store') #observer
export default class Parent1 extends React.Component {
// .....
componentDidMount () {
this.props.store.loadParent();
After that, the error is provided: MobX observer: Store 'parentdata' is not available! Make sure it is provided by some Provider
Where did I go wrong in binding the data here?
Edit: Removing #inject and only having #observer results in: TypeError: Cannot read property 'loadParent' of undefined
Few things to address:
Assuming you named your parentData store 'store' and not 'Store' like the classname, the Provider looks like it's configured correctly
Here's how I'd change the store itself:
import { observable } from 'mobx';
const axios = require('axios');
class Store {
#observable parentdata;
loadParent = () => {
// There's no need to clone this if you're using arrow functions
axios.get("/api/parent").then((response) => {
this.parentdata = response.parentdata;
}).catch(function(error){
// Error handling
})
};
}
export default Store;
In the component, I might do this:
import { inject, observer } from 'mobx-react';
#inject('store') #observer
export default class Parent1 extends React.Component {
// ... //
componentDidMount () {
this.props.store.loadParent();
}
render() {
if (!this.props.store.parentData) { return (<div>Loading...</div>) }
const { parentData } = this.props.store
return (<pre>{JSON.stringify(parentData, null, 4)}</pre>)
}
}
My suspicion is that your store is case sensitive and mistakenly named.
A nifty tricks to debugging could be to console.log important variables or attach them to a window object to test.
eg:
class Parent1 {
componentDidMount() {
window.Parent1 = this
window.Parent1Props = this.props
window.Store = this.props.store // or `this.props.Store` check case sensitivity!
}
// Open browser console and try to access your now global variables

Resources