Dynamically created component is not binding to the model on model change - javascript

My goal is on emitting of new value to the item$ property of the dynamically created component, restore component state to default state which is stored in object. But clearly component is not picking up the model changes.
I have tried to run the change detection on the component on each time new value is emitted. But still not picking up the value.
I have reproduced the problem here in https://stackblitz.com/edit/angular-tyhfku.
In above code HelloComponent is reusable component and HeroComponent is dynamic component which hosts HelloComponent (sorry for naming). On AppComponent I have a onclick method which emits new value on each click. Also you can change the state of each item on the DOM. But I'd like on each new value restore the state of the HeroComponent which I am trying to accomplish on Subscription but not working

It's not about Dynamically created components - try to change this to standard way and you still will have the same problem. It's about how you pass simple values to section/hello component, how you change them and how change detection mechanism in Angular works. After you change values in SectionComponent, from HeroComponent perespective nothing has really changed, Input values for SectionComponents are the same. Try to add another simple number Input property to SectionComponent, change this in HeroComponent and you will se that onChanges works fine:
https://stackblitz.com/edit/angular-za4mkd
I dont now what you want to achive, so I cant tell you right way to code this, but maybe you should consider using Control Value Accessor (if this has to be some sort of checkbox in form?).
Also you should remember that for objects (like data structures) Angular see changes only if reference changed (you can use spread operator to create a new instance of data structures).

Related

How to get Vue app container div attribute

I have a page which is being generated by my app in java (SSR) depending on some data (e.g. a publisher for some entity). I would like to create some sort of a reusable Vue component that would call an API method and request some data about the entity that is currently opened. Also in some cases there could be more than one such component on one page.
The only thing I cannot really figure out being a most-of-the-time backend developer - is how to tell a component which entity I'm trying to get. The only solution that comes to my mind is to generate the parent <div class="my-vue-component"><div> with an additional attribute, e.g. <div class="my-vue-component" publisher-id="123"><div>.
But I cannot find if there is a way to access that attribute from inside the Vue instance. (Please note that I don't have a fixed id for this div as there can be many such components on the same page referring to different data).
Any kind of advice is appreciated.
As stated in the previous answer, you will need to use props. Although since you will pass down data to multiple components and the data can change, there should be a way to respond to those changes.
For that, you will have to bind the prop with a reactive variable in your page/parent component.
So your SSR code should look like
<my-vue-component :publisher-id="openId"></blog-post>
And inside your page/parent component will reside the openId, which you can change as needed, and your component will re-render if prop passed to it changes.
export default {
data(){
return {
openId:1
}
}
}
It seems like you are looking for components-props.
You can define a prop like
Vue.component('blog-post', {
// camelCase in JavaScript
props: ['postTitle'],
Your SSR code should then be generating:
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
Inside the component methods you can access the passed in value using this.postTitle

Sibling component does not receive emitted changes

In my Angular 9 project I have 2 components which are siblings and the parent component. On change in component A, I emit a value and it's set in the parent component and calls a method in component B. The method in component B emits another value and it's set in the parent component. The on change in component A continues, but the emitted value from component B that is set in the parent component (which is an input in component A) is not changed. I don't know why it's not the input for component A does not change even though the parent updates the value.
Parent Component
setSomeNum(someNum: number) {
// this is run on someNumberEmitter in Component A
this.num = someNum;
if (this.viewChildComponentB) {
this.viewChildComponentB.remove(someNum);
}
}
setSomeOtherNum (someOtherNum: number) {
// this is run on someDiffNumEmitter in Component B
this.otherNum = someOtherNum
}
Component A
componentAOnChange(someNum: number) {
this.someNumberEmitter.emit(someNum);
// this.inputFromComponentB is the original value instead of the one emitted in Component B (this.someDiffNum)
this.someService.applyCalc(someNum, this.inputFromComponentB);
}
Component B
remove(someNum: number) {
this.someDiffNumEmitter.emit(this.someDiffNum);
this.someService.applyCalc(someNum, this.someDiffNum);
}
I'm using the OnPush change detection strategy, but nothing changed. How can the sibling component A run with the data changes from component B?
I'm not sure why you're using ViewChild there but if it is to update the child components manually when there's change then that should be a red flag something is being done wrong, if you have data that needs to be shared it should be shared across the board and update accordingly on the single source of data changes without having to manually update the rest of the places.
Now to your problem:
If you're using the OnPush change detection strategy you have to update your data in an immutable way or use Observables, otherwise the change detection won't trigger.
Some people will advice triggering change detection manually but I'd recommend avoiding that as the whole point of using OnPush is to avoid a whole page render unnecessarily.
A simple solution I like to use is to use a Subject or BehaviorSubject instead with the async pipe. This way it ensures smooth work with the OnPush change detection strategy because ChangeDetection will run when the Observable emits a new value, and the async pipe takes care of unsubscribing the Observable for you.
If I were to modify your current components, it'd look something like this:
Parent:
num$ = new Subject<number>();
otherNum$ = new Subject<number>();
setSomeNum(someNum: number) {
this.num$.next(someNum);
}
setSomeOtherNum (someOtherNum: number) {
// this is run on someDiffNumEmitter in Component B
this.otherNum$.next(someOtherNum)
}
Then in the HTML you can use the async pipe, like this:
<some-component [num]="num$ | async" [otherNum]="otherNum$ | async"></some-component>
(You could use the async pipe in the component itself, doesn't really matter).
And that's pretty much it. You should have a Subject as an Observable, then share it with child components, once the Observable is updated, the child components data will be updated as well.
One small caveat is that when using a Subject instead of a BehaviorSubject is to make sure to subscribe before emitting any values to the Subject, otherwise the data will not update. So for certain cases BehaviorSubject is a better fit.

How to access state variable in static functions `title` or `navigate` of the custom WeekView class

I am trying to have a custom week view as per https://github.com/jquense/react-big-calendar/blob/master/examples/demos/customView.js.
In that example, they have taken a custom number of days as 3. I want to have it dynamic (by keeping state variable). I am planning to change the state variable based on the screen size. (I have put the window width event listener to update that state variable)
Now the problem is how can I access that state variable inside the navigate and title static functions? Because they will be custom based on the no of days.
If the custom view was a React function component, and your state value was defined in a wrapping context, you could use hooks, and use a custom context hook inside the custom week view component for access to the state value.

Is there a way to call a child-component's function from another child?

I'm contributing to an open-sourced React/Redux application built using ES6 JavaScript. I'm fairly new to React/Redux so I'm having some trouble.
I have a parent class that's rendering two different React components. The first component contains some input fields regarding events (called NewShift). The second component is a calendar that renders these events (called Index).
Once a user fills out the input fields and presses a button in the first component, I want to be able to re-render the calendar in the second component. If the re-render function is in the calendar component, how do I call it from the input fields component (both children).
React re-renders components whenever component state is changed. Should you be using just React, this would mean passing changed values up to the parent component's state to force a re-render.
However, Redux makes this easier on you, as it's 'Store' functions as a global state. You can force a re-render by changing appropriate variables within the store.
Given your situation: the button should get this within it's onClick attribute:
onClick={() => dispatchNewCalendarInfo(payload)}.
dispatchNewCalenderInfo should also be imported by the component:
import { dispatchNewCalendarInfo } from './redux/path/to/post/actions.js'; and connected to it: export default connect(()=>({}), { dispatchNewCalendarInfo })(Component);. Note, you need to also import connect from 'react-redux' for this.
And, of course, dispatchNewCalendarInfo should be present in the actions.js path, and accepted by the store reducer. This dispatch should alter information that the calendar is connected to, which will force it to update and re-paint.
If you're not using Redux there's another path you can take. Instead of having the function that takes input be in NewShift, have new shift receive the function as a prop from the parent.
So in your NewShift component you would have something like onClick={this.props.submitCalanderInfo()}
The submitCalanderInfo function would be part of the parent component. You would probably want this new info to be saved into the state of the parent component, and then then use that state to update the props on the calendar or Index component. So Index might look something like this:
<Index shiftData={this.state.shiftData} />

Custom function for onPush change detection in Angular 2

{ id:123, version 1, ...}
I am writing an Angular 2 component that uses the onPush change detection strategy. I'd like to know if there is a way to use custom logic with onPush when determining if an object has changed. My understanding is that onPush checks the object reference an so only updates when a new instance of an object is sent.
My app tracks its own versioning for objects which means that every object has an id and version number. I periodically refresh data from the server which means that a new object is instantiated even though the data has not actually changed. This means there are cases with the default onPush that would see a new instantiated object and think it has to update. In actuality the id and version number are the same so even though the the object reference has changed I can skip updating the component.
I'd like to be able to provide a custom function to onPush that essentially uses a function like this to do change checking.
(obj1, obj2) => obj1.id === obj2.id && obj1.version === obj2.version
Is it possible to customize the onPush logic, or is there another way to achieve this so that I don't need to unnecessarily update the component when the object reference changes but the data does not.
I don't think that it's possible to create a custom changeDetectionStrategy . But if you do track the change on your objects by yourself you can do something (probably) even more optimized.
You can inject the ChangeDetectorRef and tell Angular that your component shouldn't be watched anymore (which is pretty cool and powerful !).
constructor(private _cd: ChangeDetectorRef)
ngOnInit() {
this._cd.detach();
}
ngOnChanges() {
// check if your objects have changed here
// if they've changed, tells Angular to check
// the bindings manually
this._cd.detectChanges();
}

Categories

Resources