Agreed with you. A lot of stuff across the internet just shows a pretty simple examples or goes into too deep low-level stuff, and it's hard to grasp what's going on. But this guy made it very simple (just need to know that fancy magic injector, NgControl and FormGroupDirective )
Thanks a lot for watching and for that feedback mate! 🙏 If you want more content like this, please subscribe and make suggestions on things you would like to learn more about 🙏
public writeValue(outsideValue: T): void { if (this.control) { this.control.setValue(outsideValue); } else { this.control = new FormControl(outsideValue); } } there will be a cyclic change in value... 1. change the value of the external control 2. writeValue is called 3. let's take the first step
Very interesting video. A few things that will come in handy. The question is on the directive you created to extend from. It looks just like a base class - why dioes it have to be a directive, perhaps for the injection of the form directive?
so this approach basically gets the formControl from the parent component and places it on the nested input. doesn't a ControlValueAccessor allow us to bypass that? what advantage does this have over simply using HTML's native (change) and then calling the CVA's onChange() function with that value? for example, most documentation I've seen has the registerOnTouched function contain a single line "this.onTouched = fn". why is this one so much more involved? just trying to understand. this looks amazing and really in-depth I'm just curious why this approach differs so much from other ControlValueAccessor documentation I've seen
Good question mate. CVA allows us to use formControl and formControlName on custom components which makes it easier for us to standardise the workflow across multiple form elements. OnTouched is used to indicate control states that User has focused on the input. You can extend the logic to reset the touched state to hide errors when typing and making the errors re-appear onBlur. This way, we can also standardise the behaviour of the inputs, UX wise.
When i add the component and use a formGroup, when i reset the form with this.form.reset(); the component causes infinit loop in writeValue function in control-value-acessor, can you have this problem ? Edit: i fix this error: in writeValue function (this.control && this.control.value!=value) resolve to me.
Great details. Absolutely loved it. Just one request, can you update validation-errors.component.ts file for loop as per latest angular version (17)? While rest of the things are working as expected. But I am getting an error "Type 'Record' must have a '[Symbol.iterator]()' method that returns an iterator"
Hello again) Found out another problem trying to removeControl() in formGroup. I get an error: "here is no formcontrol instance attached to form control element" It happens in directive, registerOnChange method, when doing tap((val) => fn(val)) I m using your approach in my project, but cant get rid of this error. Could you advise how to fix it? Thanks!
Good question mate. To make it automatically select the initial value, patch the key, which might be the ID of that object. Then you need to set up logic to show the selected value by another key - which shows the name/title of that item in that object. Having a fallback option like option[0] could be handled in many ways, but if you want to ensure that the control also receives that value - you'll need to override the ngOnInit function and call to patch the value there. If the data is retrieved async - it might be more trivial to set up a listener for the "first" change of that object. It's difficult to give the exact answer without knowing what you want the end result to be/turn out like.
@@DevBySeb I was patching after getting data from an api but even if I comment that code out and just setup the form group from the constructor all form fields seem to be touched and dirty for some reason
Good question. You can create a function that marks all controls as dirty and touched when pressing a certain Button. You can also remove the mark as touched from the directive
Great explanation dude, I am getting error "Maximum call stack size exceeded" while writing the value. Could you please help me out where i can resolve this :)
@@DevBySeb But if i do that my select component giving some error called "Cannot read properties of undefined (reading 'value') at SelectComponent.writeValue "
@@DevBySeb If i am doing that i am getting error like this for my select component "Cannot read properties of undefined (reading 'value') at SelectComponent.writeValue "
the thing was, it was entering an infinite loop when i try to do whatever from the outside programatically. But the above mentioned fixed the issue :)@@DevBySeb
to be more specific, I was trying to reset the "custom select" on valueChanges in another control of the form, but then it went to infinite loop. this line - if (this.control.value === value) return; in the writeValue method fixed it. @@DevBySeb
I seem to have run into a bug with this code, FYI. I'm using Reactive Forms and all works for the most part. But, I have the need to update the value of the control based on another event, so I call myform.get("someinput")?.setValue("new value") and then my app crashes with stack overflow error. Calling SetValue causes the SetValue in the Directive to be called and on and on until boom
I have an issue, with this on cancel the errors show up because I have this code @if(control.invalid && control.touched && (control.touched || control.dirty)) { } I need to have messages show up on save button when empty but not on cancel when I touch the control, so I have to have the check if the control was touched, then it throws a message but if I touch and then cancel I see the message first before the modal closed
@@DevBySeb i appreciate immensely your response, I’ll try this tomorrow and I thought about that as well, that’s a known issue with modals and forms, and I’m going to have a lot of forms with modals. Again thank you so much, will let you know how it’ll turn out.
@@DevBySeb Nothing worked because onChange in the validator would kick in before cancel event from the component, so I found a solution instead of click on button do mousedown!!! I would hope there is a better way but this worked, I’m will not sure what the code you wrote really for registeronchange does why not do this._onChange = fn, why do subscribe etc?