DEV Community

Discussion on: Angular - Zoned Out !

Collapse
 
suvi profile image
Suvendu Karmakar • Edited

Hey @ezzabuzaid , Thanks for your comment. I should have really explained the situation better here.

So I tried this with interceptors and opted the ZoneJs solution because of the following points :

  • The API calls which looks very simple here are actually 10+ services 100+ api calls and all kinds of forkjoins / flatMaps.
  • As I am checking with URL, if the URL is what I need, consider a scenario where 2 URLs which are almost identical in structure but I want to track one and don't want to track other . ZoneJS makes easy enough to run inside zone the one I want to track. While with interceptors it'll be a lot of if checks, which makes the code less maintainable.
  • Lastly I wanted to trigger the loader only after user hits the route, which is triggered inside a route resolver , which was very hard to do with an interceptor.

Making ngZone['_inner'] and task._state private was a helpful suggestion. I would definitely keep that in mind.

Up for a further discussion on this. ✌️

Collapse
 
inaitana profile image
Ivan Naitana • Edited

He's not telling you to "make ngZone['_inner'] and task._state private", since I don't think you're a ZoneJS mantainer.

He's telling you that you are accessing private ZoneJS properties , and sorry but this is just plain wrong.
You are using undocumented features you probably copied from somewhere, and, even worse, you are advising others to use them.

This is always wrong (in any programming language) for at least two reasons:

1) You can't really know what's going on here. Unless you can know why exactly you are forking the _inner zone in that exact moment and how it is exactly handled itnernally, this would be random hocus pocus to you, that somehow does its purpose. If you can't understand how something works exactly, you will have a hard time debugging it.

2) If something is private and undocumented, it's just not supposed to be used from the general public. Thus, it can be subject to hard changes at any time, and without any notice.

I.E: maybe one day task objects might no longer have a "data" property, so task['data']['url'] will fail.
This doesn't mean the advice would be "always check if tasks have a data property". This means "don't use the undocumented data property".

Also, I didn't try this but in Angular trying to access private properties might throw hard exceptions when compiling AOT.

You can write a correct solution using an Interceptor, which is pretty standard and documented, and way more clean.

If you define all your messages in a Model, and use your Component correctly, you can do everything with a Service, a Model, a Component and an Interceptor, and a lot less custom code.
The Interceptor will read the correct message from the Model, call a method on the Service that will publish it, and update the Component. If you need more data to be shared with the Component, you can do it on the Service.

More on this, having message "ids" and then matching them with routes in long custom if chains looks like a lot of overhead.
You would most probably rather have a route attribute in your messages (which could be a regex) and match with it.

Honestly, I don't want to be too harsh or judgemental, but even your basic solution doesn't seem to follow Angular best practices.
So it's nice of you to want to help people with your tutorials, but you would make people a bad disservice if you point them the wrong ways.

Your Component gets an Input "messages" object (and for some reason an Output "loadingEmitter" whose purpose you never explain), and your Service has a "messageSubject". But you never show how one acts on the other.

Worse, republishing this.loaderMessages on the messageSubject is just plain wrong.
Javascript objects are always passed by reference, so whatever has access to the published messages object will always have access to the current version of it (with the updated active flags). There's no need to republish it.

You are probably doing it to trigger Change Detection, but even this doesn't add up. Unless you are doing some magic somewhere outside of the Component to force it, the component's ngOnChanges should never be fired, since the Input property is always a reference to the same object, republished but not changed.
That is, unless you are subscribing to the messageSubject (which you don't show) and cloning the object before passing it to the Component, or something like that.

Using an Observable is correct, but the Component itself should subscribe to that Observable, and update the template accordingly. There's no need to force an Input property into it.
Also, that Observable should probably emit the current active message. This way you can easily have proper Change Detection.

Thread Thread
 
suvi profile image
Suvendu Karmakar • Edited

Hey Ivan , Thanks for your kind comment. Let me calmly clarify you certain things.

First of all, thanks a lot for taking time to drop a detailed comment, I really appreciate it. Let me talk about everything one by one.

I missed the meaning of private property part, I thought what he meant was to keep these properties private to your zone, I apologise for that.

The part about copying stuff from somewhere, I am pretty sure you copy stuff from articles / blogs too, as I don't think you are on the development team of Angular or something significant for that matter. (I gave the blog link for everyone to clarify their doubts). Also I said I solved the problem like this, and did not ADVICE anyone to use it, as far as I know there are no single solutions in engineering. You can chose to ignore the solutions you don't like.

Okay I might know what's going on here as I am still learning and also writing my first blog here, but I think you you're so intimidated because you definitely don't know anything what's going on here. I have read 10+ articles on ZoneJS, watched videos and read documentation, and I can certainly explain what is "forking the _inner zone" , we can discuss this off the comment section.

Private and undocumented things are not supposed to be used ??? Then I am sure you're well versed with ZoneJS documentation, please direct me to the place where this is mentioned that "DON'T use ZoneJS , it's a hidden feature made for internal use". ZONEJS is not a hack, just to clarify. It's available at 'angular/core'. I don't think I need to explain core to you.

Your solution with interceptors , let me give you a scenario. There are two arrays (A & B)of parallel API calls merged into an observable using lets say "forkJoin" in the same service. Both the arrays have one url which is same, I want to track the url from A and not from B, can interceptor handle that. Instead of suggesting solutions for how to make the message service work, try to fix this problem, which I am sure you did not get properly.

May be the ids solution is an overhead, I am sure I can do better there. You're right there.

About the component accepting messages array, loaderEmitter etc and whose purpose I did not mention. Again if you understood the point of the post you would not asked this question. I have written "/* Actual code removed for the sake of brevity. */" . That means something, that means the code is not important for this blog's perspective.

Okay lastly, broadcasting this.loaderMessages on the messageSubject is just plain wrong . I am so puzzled at this, obviously I know JS objects are passed by reference, and in fact I am using change detection strategy- onPush. Quick Angular tip for you, whenever you do that you use ngDoCheck not ngOnChanges. Also, the purpose of broadcasting the whole array was to do some calculation on all the subscribers as soon as it happens, as I haven't implemented ngDoCheck.

Again these are the things, which were just there to give you a glimpse of the working of the loader, which could have been implemented in 100 different ways. Commenting on that is just digressing from the topic.

I am so baffled that how people with no background information about the application, can judge and pass comments about the code. Also it's not an advice to follow this approach to achieve it, it's just me playing around with the code.

Hope this helps you understand things a little better and being little less hateful with your comments.

PEACE !

Thread Thread
 
inaitana profile image
Ivan Naitana

Hi Suvendu,

I clearly failed in not making my comment sound judgemental.
As much as you say you thank me and appreciate it, the sound of your answer ("I don't know if you can read English properly", "I only do educated debates", "before furiously tapping your keyboard") clearly shows you found it offensive.
I didn't mean that and I'm sincerely sorry if you found it "hateful".

You say you are not advising people to use your solution, but your post is literally titled "A short guide to understand ZoneJs and to solve a problem".

If your solution involves accessing private properties of Angular internals, it's a wrong solution.
You are free to think otherwise, but you are never supposed to access private properties. Of course you won't find any documentation saying you're not supposed to, since it's already taken for granted.
Even if you don't believe it's just wrong, you can find two valid pratical reasons not to do it in my previous comment.
And I really wonder if your code would compile in production.

You are right in saying I don't know the specifics of your project, but I don't agree that should hold me from commenting on that.
If you want to write a guide that says using undocumented features is better then using documented and standard ones, you should point out in which exact scenario this is true. If you hide it, it will sound like overcomplicating.

To answer your question about the Interceptor, I can't be more precise since as you say I don't know the details, but an idea could be adding params to the http query instructing the Interceptor on how to handle it. Or maybe using the Service to handle communication between what is running the query, the Interceptor and/or the Component.

Lastly, re-emitting the same object is always a bad practice. You are showing this in your code, then you're showing a bad practice. You might be doing something that you hide to force change detection, and I don't know what exactly, but that's because you are using a bad practice.
I don't want to force this on you, so you can take it as just a matter of personal preference.

Again, sorry if you found my comments offensive, I really didn't mean it.

For what it's worth, I sincerely like your writing and find it engaging, and that's why I read the whole article even if I was puzzled at the code.

If I criticized your code is because I like your style, and thought it would be better if you sticked on writing about documented code and good practices.

If I didn't like anything about your post, I sure would have ignored it, I didn't mean to write a destructive comment.

Thread Thread
 
suvi profile image
Suvendu Karmakar • Edited

Hi Ivan ,

Sorry for lashing out , I edited my above comment with better phrases which do not sound offensive. I am certainly here to learn from everyone in the comment section . It's very hard not to take offense on the phrases you used like (You don't really know what's going on here, hocus pocus , etc). Could have easily been rephrased in a better way. In sounds to be destructive that way.

The title of the blog ("A short guide to understand ZoneJs and to solve a problem.") is subject to interpretations, I myself never just read one blog and implement anything. So it depends how you interpret it.

My code is compiled and deployed at at least 10 clients locations, including some big IT giants like Biocon, and even at organizations like ISRO etc. I don't want you to take it the wrong way, but please read a bit about ZoneJS, it's not much mysterious and cryptic. I can even refer you some good blogs. Because most of the things you say are wrong are just your opinions. Again, I mean no offense.

Also everything we discussing is kinda debatable except broadcasting an array, that can be done in a better way. The only thing I beg to differ is your interceptor approach in the current context. We can connect outside this comment section and discuss that if you like.

Sorry again for using those phrases, i should have handled it better.

Thanks , Cheers ! :)

Thread Thread
 
inaitana profile image
Ivan Naitana

Hi Suvendu,

thank you for accepting my goodwill and softening the tones.
As you edited your comment, I also edited my first one to clarify parts that indeed, now that you highlight them, could sound offensive.

I know that there are guides about ZoneJS, and you sure read a lot more than me about it, so you sure have a better picture than me. But those guides are not official, the official documentation is pretty scanty about it.
When I wrote "you don't really know what's going on" I didn't mean you don't know because of your lack of knowledge, I mean you (or me) don't know because there's no way to know (I now edited that part).

Even if people "reverse engineered" it and wrote guides, do they really know exactly when and how the _inner zone gets updated? Why should we fork the _inner one and not the _outer one? Has it always been consistent in all Angular versions? Why aren't we using the forkInnerZoneWithAngularBehavior() method instead? What does AngularBehavior even mean?

Of course I do copy code on an almost daily basis, but if I copy something from an unofficial source, something which is undocumented but only explained by the author to the best of his knowledge, I admit it indeed is hocus pocus. With which I mean something that just works that way because it does, and it's not guaranteed to work perfectly and forever to my needs. And if I wanted to change something about it I wouldn't know where exactly to look other than unofficial guides by people who write to the best of their knowledge.
I'm not saying it doesn't happen to me, but it's not a good practice, so if there's a documented and more conventional alternative I prefer it.

Also, given the rate that Angular introduces breaking changes in documented features, I wouldn't be surprised at all if they introduced them in an undocumented one (which as far as they know is only used in Angular itself). And of course the breaking changes would be undocumented themselves.

I believe you when you say you do use that code in production, but it honestly sounds weird that it doesn't throw compiling exceptions when accessing private properties, at least with Ivy.
Maybe I will try it out of curiosity when I get back to work (now I am on holiday, though it doesn't look like so;)).

Thank you again for helping me not escalating the argument, and keep on with your blogging. As I already wrote I like your style, it sure doesn't look like someone's first post in any negative way!

If you ask me why I don't write my own blog instead than criticizing your code, the answer is that I would do a terrible job, so it's better to leave it to you.
Maybe with more constructive and well worded comments from people:)

Thread Thread
 
suvi profile image
Suvendu Karmakar

Hey Ivan ,

Thanks for taking high grounds man ! Let's do our bits to develop the community. Me with my poorly chosen codes XD and you with your constructive comments. :D
I will surely come up with a better / well researched blog on ZoneJS in future and definitely tag you there.
Again, thanks for all the compliments about my writing, I really appreciate it.

Cheers :)