How do I refresh a cell using Vue3 composition and child to child communication with AG-Grid - ag-grid

Let's say I have two child components A and B
A has a button that should add a value to a grid select box column and B has the grid which has a vue select box for a column using
cellRenderer: 'tag-grid-select',
I want to be able to click on the button in A to refresh the select component in the grid in component B.
Note: This is not parent to child communication but child to child specifically using the Vue3 composition api and setup().

I was able to solve this using an eventbus. With this you can communicate with any component regardless of the relationship. I use npm package mitt
Here is some code I used for child to child communication
Component A -- contains ag-grid-vue
export default {
setup() {
return {
gridApi: null,
gridColumnApi: null,
}
},
async mounted() {
this.eventBus.on('refreshGrid', (args) => {
this.refreshGrid(args)
})
}
methods:
{
refreshGrid(params) {
this.gridApi.redrawRows()
},
async onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
}
}
Component B - function that emits the command to be received by Component A
this.eventBus.emit('refreshGrid', {yourdata})
You will need to import and setup mitt according to their docs. I added it to my main.js so I did not have to import it in any page.
import mitt from 'mitt'
const eventBus = mitt()
app.config.globalProperties.eventBus = eventBus

Related

How to test the component refresh behavior with react-testing-library?

I'm writing a test for a component that takes a few props such as "isLoading", "clients" and "refreshClients". refreshClients is defined like this:
function refreshClients() {
setIsLoading(true)
getClients().then(response => {
setClients(response)
setIsLoading(false)
})
}
clients and isLoading are states from the parent component that are used as props of the child component. The client component also gets the refreshClients prop, which allows it to update its own props (isLoading and clients), through the function passed in by the parent component.
This is one of the use cases: after taking an action over a client, like deletion, the component will call refreshClients, which should take care of reloading the clients table displayed in the component. While the new listing is being loaded the table isn't displayed (isLoading is true). The component works well, however I'm unsure on how to properly test it using testing-library. I'm basically calling rerender in the tests but I feel there should be a way to replicate this behavior in the tests...
Is there a way to create states to pass as props to the tested component? Or is there another recommended approach to handle cases like this?
In case it makes it easier to visualize the idea, here is a complete simple example of how it would work:
import {createRoot} from 'react-dom'
import React, {useState} from 'react';
export function App() {
const [isLoading, setIsLoading] = useState(false);
const [clients, setClients] = useState(['david', 'sara']);
const refreshClients = () => {
setIsLoading(true)
setTimeout(() => {
setClients(['john', 'mary'])
setIsLoading(false)
}, 1000)
}
return <ClientsTable isLoading={isLoading} clients={clients} refreshClients={refreshClients} />
}
function ClientsTable({ isLoading, clients, refreshClients}) {
const deleteClient = () => {
console.log('TODO: delete client')
refreshClients()
}
return (
<div>
{isLoading && <p>Loading... please wait</p>}
{!isLoading && clients.map(client => (
<div>{client} <button onClick={deleteClient}>delete</button></div>
))}
</div>
);
}
createRoot(
document.getElementById('root')
).render(<App />)

Events provider is deprecating. Using Redux or Observables for state in ionic apps

I've been using events in my ionic application, where i subscribe in one page, and publish the event in the other page. Now I see a warning that Events are going to be changed with Observables and Redux state and effect.
I was using Events mainly to call for component function changes outside it, so I had a components for example:
Component1.ts
this.events.subscribe('event:addValue1', (data: any) => {
this.valueName = 'VALUE1';
});
this.events.subscribe('event:addValue2', (data: any) => {
this.valueName = 'VALUE2';
});
and than outside this component I was calling the publish methods from any page, like:
Page1.ts
this.events.publish('event:addValue1');
Page2.ts
this.events.publish('event:addValue2');
By this i was able to change the data (this.valueName) outside the Component1.ts from any other page, simply by publishing the desired event.
I know that this might not sound or be right approach, but It was the only way I was doing changes to my Component1.ts outside it from any page.
I have now changed this and just put separate functions and than i access them via ViewChild component name like
#ViewChild('component') component: any;
....
this.component.functionAddValue1().
and additionally I send additional params via Angular NavigationExtras if i need to calculate and call some function from the Component1.ts, lets say if I navigate to some route.
Before this I was just calling the events.publish and I was able to make the changes to the Component1.ts on the fly.
Create event service.
In the EventService.ts:
export class EventService {
private dataObserved = new BehaviorSubject<any>('');
currentEvent = this.dataObserved.asObservable();
constructo(){}
publish(param):void {
this.dataObserved.next(param);
}
}
For publishing the event from example page1:
constructor(public eventService:EventService){}
updatePost(value){
this.eventService.publish({name:'post:updated',params:value});
}
In page 2:
constructor(public eventService:EventService){
eventService.currentEvent.subscribe(value=>{
if(value.name=='post:updated'){
//get value.name
}else if(value.name=='another:event'){
//get value or update view or trigger function or method...
}
// here you can get the value or do whatever you want
});
}

Passing data from the child modal to the parent

When I created a SeleccionServicioComponentMD modal window (child), I used this way:https://valor-software.com/ngx-bootstrap/#/modals#service-component
Inside the child there is button. When it is clicked:
1) the parent should close this child.
2) the parent should display another modal.
My attempt: The child (modal) emits an event to its parent but:
3) the parent didn't include an <app-seleccion-servicio-component> tag inside its HTML because its child was dynamically created. So, where does the parent listen for this emitted event from its children?
The expected result is:
4) click on the button inside the child component.
5) the parent closes this child (modal window).
6) the parent shows another modal window.
7) I am stuck on this point. I don't know how to do so that the parent listens the event emitted by its parent with no <app-seleccion-servicio-component> tag.
Can't say much without looking at your code but you can create an EventEmitter in your child component and subscribe to it from parent.
Example: https://plnkr.co/edit/b6qHpolJmUFy7dYvYpkJ?p=preview
/* CHILD COMPONENT */
public event: EventEmitter<any> = new EventEmitter();
triggerEvent() {
this.event.emit({data: 12345});
}
/* PARENT COMPONENT */
this.bsModalRef.content.event.subscribe(data => {
console.log('Child component\'s event was triggered', data);
});
Related to Angular 7, I could managed the scenario as follows.
parent-component.ts
bsModalRef: BsModalRef;
loadModal() {
const initialState = {
title: 'Appointments'
};
this.bsModalRef = this.modalService.show(ModalComponent, {
initialState,
class: 'modal-lg'
});
this.bsModalRef.content.messageEvent.subscribe(data => {
console.log('Child component\'s event was triggered', data);
});
}
parent-component.html
<button type="button" (click)="loadModal()">Open Modal</button>
modal-component.ts
#Output() messageEvent = new EventEmitter<string>();
private submit(){
let msg = "Test Message";
this.messageEvent.emit(msg);
this.bsModalRef.hide()
}
modal-component.html
<button (click)="submit()">Submit</button>

React/Redux and Websockets for Timer actions

Here is my use case:
I have two different apps, react client app and express/node backend server app having REST APIs. I want the react client app to refresh the component states, every time the Server sends an event on the socket which has change of the data on the server side.
I have seen examples of websocket doing this (http://www.thegreatcodeadventure.com/real-time-react-with-socket-io-building-a-pair-programming-app/) but in this case the client and the server components are in the same app. How to do this when you different apps for client and the server components.
Should I use Timer (https://github.com/reactjs/react-timer-mixin) to make a call from the client to the server rest endpoint and refresh the components on the client if there is any change in data. Or does redux middleware provide those capabilities..
thanks, Rajesh
I think what you are looking for is something like react-redux. This allows you to connect the component to depend on a piece of the state tree and will be updated whenever the state changes (as long as you are applying new references). See below:
UserListContainer.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as UserActions from '../actions/userActions';
import UserList from '../components/UserList';
class UserListContainer {
// Subscribe to changes when the component mounts
componentDidMount() {
// This function
this.props.UserActions.subscribe();
}
render() {
return <UserList {...props} />
}
}
// Add users to props (this.props.users)
const mapStateToProps = (state) => ({
users: state.users,
});
// Add actions to props
const mapDispatchToProps = () => ({
UserActions
});
// Connect the component so that it has access to the store
// and dispatch functions (Higher order component)
export default connect(mapStateToProps)(UserListContainer);
UserList.jsx
import React from 'react';
export default ({ users }) => (
<ul>
{
users.map((user) => (
<li key={user.id}>{user.fullname}</li>
));
}
</ul>
);
UserActions.js
const socket = new WebSocket("ws://www.example.com/socketserver");
// An action creator that is returns a function to a dispatch is a thunk
// See: redux-thunk
export const subscribe = () => (dispatch) => {
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'user add') {
// Dispatch ADD_USER to be caught in the reducer
dispatch({
type: 'ADD_USER',
payload: {
data.user
}
});
}
// Other types to change state...
};
};
Explanation
Essentially what is happening is that when the container component mounts it will dispatch a subscribe action which will then listed for messages from the socket. When it receives a message it will dispatch another action base off of its type with the corresponding data which will be caught in the reducer and added to state. *Note: Do not mutate the state or the component will not reflect the changes when it is connected.
Then we connect the container component using react-redux which applies state and actions to props. So now any time the users state changes it will send it to the container component and down to the UserList component for rendering.
This is a naive approach but I believe it illustrates the solution and gets you on the right track!
Good luck and hope this helped!

Angular 2 + ngrx(redux) + forms

How do you handle Angular 2 forms in unidirectional data flow? Especially with validation between several parent/child components?
I am using ngrx/store and model driven forms with form builder.. Is it possible to do something similar like form reducer in React and make it as a part of Store?
Do you have some articles about it?
I have created a library called ngrx-forms that does exactly what you want. You can get it on npm via:
npm install ngrx-forms --save
I recommend checking out the full README on the github page, but below you can find some examples of what you need to do to get the library up and running once installed.
Import the module:
import { StoreModule } from '#ngrx/store';
import { NgrxFormsModule } from 'ngrx-forms';
import { reducers } from './reducer';
#NgModule({
declarations: [
AppComponent,
],
imports: [
NgrxFormsModule,
StoreModule.forRoot(reducers),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Add a group state somewhere in your state tree via createFormGroupState and call the formGroupReducer inside your reducer:
import { Action } from '#ngrx/store';
import { FormGroupState, createFormGroupState, formGroupReducer } from 'ngrx-forms';
export interface MyFormValue {
someTextInput: string;
someCheckbox: boolean;
nested: {
someNumber: number;
};
}
const FORM_ID = 'some globally unique string';
const initialFormState = createFormGroupState<MyFormValue>(FORM_ID, {
someTextInput: '',
someCheckbox: false,
nested: {
someNumber: 0,
},
});
export interface AppState {
someOtherField: string;
myForm: FormGroupState<MyFormValue>;
}
const initialState: AppState = {
someOtherField: '',
myForm: initialFormState,
};
export function appReducer(state = initialState, action: Action): AppState {
const myForm = formGroupReducer(state.myForm, action);
if (myForm !== state.myForm) {
state = { ...state, myForm };
}
switch (action.type) {
case 'some action type':
// modify state
return state;
default: {
return state;
}
}
}
Expose the form state inside your component:
import { Component } from '#angular/core';
import { Store } from '#ngrx/store';
import { FormGroupState } from 'ngrx-forms';
import { Observable } from 'rxjs/Observable';
import { MyFormValue } from './reducer';
#Component({
selector: 'my-component',
templateUrl: './my-component.html',
})
export class MyComponent {
formState$: Observable<FormGroupState<MyFormValue>>;
constructor(private store: Store<AppState>) {
this.formState$ = store.select(s => s.myForm);
}
}
Set the control states in your template:
<form novalidate [ngrxFormState]="(formState$ | async)">
<input type="text"
[ngrxFormControlState]="(formState$ | async).controls.someTextInput">
<input type="checkbox"
[ngrxFormControlState]="(formState$ | async).controls.someCheckbox">
<input type="number"
[ngrxFormControlState]="(formState$ | async).controls.nested.controls.someNumber">
</form>
This is a fairly old question, but I couldn't find a great solution in my own quest for working with ngrx + reactive forms in Angular. As a result, I'll post my research here with hope that it may help someone else. My solution can be broken down into two parts, and I pray you (oh weathered soul) find it applicable to your problem:
1) Monitor the form element/s (for example, "keyup" event for a typical text input), and update the State from that event. This strategy comes straight out of the book search component in the ngrx example app. We can now successfully populate the State as our form changes. Awesome! 50% done!
2) The angular reactive forms guide demonstrates creating the form group in the constructor. I have seen some other people do it inside ngOnInit, but this is too late in the lifecycle for our needs (I tried, I failed). Now that we have our form group established, setup ngOnChanges to capture any changes pushed from the state, and then update the form group using patchValue. For example:
ngOnChanges(changes: SimpleChanges) {
if (changes.valueICareAbout1) {
this.myForm.patchValue({
valueICareAbout1: changes.valueICareAbout1.currentValue
});
}
if (changes.valueICareAbout2) {
this.myForm.patchValue({
valueICareAbout2: changes.valueICareAbout2.currentValue
});
}
}
In the applications I built with Angular 2, the following guideline seemed to work well:
Parent components pass data down to children via data binding. Child components request data changes by emitting output events to parent components. It is the parent components responsibility to act accordingly.
In a hierarchical component structure, data changes are handled by the lowest component that depends on the data. If there's another component higher up or a sibling that depends on the same data item, pass changes up by emitting events and leave the handling to a higher component.
This scheme works well because, for any data that is relevant to more than one component, there is a single component responsible for performing changes. Changes bubble down automatically. Components are reusable, and changes in the component tree can be easily adapted.
With regard to validation, any component in the ladder between the lowest component emitting a data change request up to the highest component that finally handles the change, any component can effectively cancel the change by not passing it higher up. In most applications, I'd opt for validating data changes at the origin of the change though.
Naturally, child components can still have internal state and need not communicate changes - unless changes are relevant to the parent component.
Form data is inherently a very local state, especially for Angular since ngModel binds to local component variables. The top devs that I know recommend keeping the data for the form localized to that component (ie just use ngModel with local variables). This is because un-submitted form data is almost never shared by various components across your whole application. When the user submits the form then you can dispatch an action with a payload containing the form data to a parent component, to the store, or even to an ngrx/effect to be posted to a server.