New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Final statement about ngInclude alternative #7596
Comments
Also, if this just absolutely won't be supported, maybe an explanation of why would help. I've seen references to "security concerns", but what those concerns are is not clear. I don't really understand how this is different than using a templateUrl in a component. Dealing this this limitation has been a real struggle. Consider something as basic as a menu that creates tabs. There are two layers to the problem: 1) Getting a handle on the component you need to add, and 2) Actually adding the component once you have a handle on it. As far as I can tell, the only options for "Step 1" (obtaining the Component Type) to add are:
For "Step 2" (adding the component), we need to use loadIntoLocation(). However, this requires a local template variable anchor name. And local template variable names can't be dynamic. Which means we must resort to bizarre workarounds like this to create a fake wrapper component with a known (and isolated) anchor to target. Basically, this whole situation is way too complicated for something as basic as adding a dynamic tab. And obviously, the problem goes way beyond tabs. Tabs are just an obvious way to demonstrate the problem. I think this requires some thought from the team, because this simply should not be as difficult as it currently seems to be. That said, if I'm missing some key motivation for why this complexity is deliberate, I'm open to hear more details on why. |
IMHO ngInclude is only a nice to have since we can already generate components dynamically and load them with the DynamicComponentLoader. That said, it would be a good idea to have a (third party?) service to facilitate this case or at least have examples in the doc for those who come from ng1. |
That's the thing. Yes, it's possible to create components dynamically. The problem is that it's currently far more complicated than it should be for something this fundamental and necessary. (See my earlier comment.) |
@PavelPZ Maybe I am missing something but it seems pretty straightforward. Why not something like that:
It might not work out of the box but you get the idea. You should also cache your components in a service instead of creating a new one on every init. EDIT: @PavelPZ Deleted his comment but this is a reply to that: http://stackoverflow.com/questions/36008476/how-to-realize-website-with-hundreds-of-pages-in-angular2 |
Again, this whole "manually-create-a-fake-wrapper-component-on-the-fly" approach is decidedly un-straightforward. If you already know about this trick you can obviously make it work, but very few people would ever realize this on their own. If this is really the way the Angular team think this should work, then I'd say the DynamicComponentLoader (or something else in the library) should expose a method to wrap up this logic so that people aren't left pulling their hair out trying to figure this out. Maybe a loadTemplateUrl() method that takes a template path instead of a Type reference? |
@jpleclerc thanks a lot. I will try your tricky solution. The most interesting aspect of that solution is that during multiple calls of ngOnInit there exist multiple declarations of ArticleFakeComponent ES6 class. What is the JavaScript strategy when instantiating this class? Maybe "last declaration wins" and previous declarations are released? When a user loads 100 web articles by this hack, what happens with the previous ArticleFakeComponent declarations (containing decorator with template)? Are all resources released correctly or do they remain in the memory? As @brian428 mentioned, some official support or confirmation form Angular team will help a lot. |
@brian428 I agree with you. But I feel that the real problem is the lack of documentation in this regard and not the lack of feature. Implementing a generic service to manage that use case would take at most 4 hours of work. |
@jpleclerc that may well be true. But it still seems silly to have this work manually re-done over and over, when it could (and should, IMO) just be built into the framework. If this was some bizarre edge case, having people handle this themselves might make sense. But for something as widely needed as this is, it really seems like it should be part of the framework. |
@mhevery mentioned this in the other issue, but i'll repeat it here for clarity - a "template" is no longer a standalone thing in Angular2 - the base unit is component The major difference to understand is that in real-world angular2 application, template compilation will happen offline, that is, as a build-step - where your template string will be transformed into executable javascript. This provides a major boost in performance as well as meaning we don't have to ship the compiler code to a real application, saving bytes. @jpleclerc's example works, but again, would require the template compiler to be shipped to the browser at runtime. A component is just a javascript class. Yes, you could use the System loader to load them dynamically (again - you'd be loading a pre-compiled component, ideally...), but equally you could import a module that exported any number of Components and simply reference them by name - see an example here: https://plnkr.co/edit/C0U5IIflrMnqxuXVbdw8?p=preview As far "should be built into the framework" - DynamicComponentLoader is a low-level service, and it exists so that higher level services (like our own Router) can leverage it. It's impossible for us to cover all use cases, and so we expose the same primitive the framework uses for your own usage. |
Thanks, Rob. This helps, as I hadn't thought of the "import *" approach, and also hadn't realized that you can specify the same local template variable name as the target location for multiple consecutive components. I had (wrongly) thought this required unique target locations. Obviously a big chunk of the problem (for me at least) is the lack of understanding about what the various options are. So far, it's just been a lot of blind experimentation. Having these in the docs would probably help a lot. I'll see if I can spend some time over the weekend to update the docs for DynamicComponentLoader to include this example (along with one or two others, possibly). |
Hi, Thanks for the very helpful comment #7596 (comment). So let's recap. Let's say that i have 2 different components with exact the same controller but different templates. In angular1 i would make the template url dynamic or use ng-include. In angular2 what would be the best way to reuse the same class? Is there a better way than inheritance. As i understand the injection of parameters and inputs don't work with base classes and this would lead to code duplication. So if we take the plunkr https://plnkr.co/edit/C0U5IIflrMnqxuXVbdw8?p=preview it would be nice to add that foo-component and bar-component should have the same inputs and also a logic in the controller. If yes then what would be the best way for the code sharing. Thanks, |
I'm currently deciding if we switch to Angular 2, or not, in a project that we are starting, and this is the main problem. We are changing the UI layer of a web application, we have too many screens, we have too many entities and I we can't to write a component for each entity. Currently we have about 400 entities and we have at least a CRUD screen for each entity, where you can query, edit, create and delete entities. The project is started using angular 1, one month ago, we have "only one" component (1.5 angular.component()), called CrudComponent and have an input value: the entity name.
CrudComponent search for Well, I'm trying to build this system over angular 2 and I'm having problems, of course. I could assume to have a component for each enity, although this means having 800 files instead of 400 ... but the problem is to compose the component template, using the speciallization of each entity. When I see this thread, this issue, I'm starting to think that angular 2 team don't want to support it and I'm searching for other ways to implement it. Perhaps we could compose the final template for component if I could use a promise for
This way I could to build the final template for my crud component without use any "tricky" solution. What do you think about? |
use multi-content projection. http://blog.thoughtram.io/angular/2015/04/09/developing-a-tabs-component-in-angular-2.html <custom-component #myRef> |
@damiandennis yes, I have taken this way, but continue having problems. |
@tolemac If you have more than one |
Something like
The solution is that you need to wrap your templates into components, and then you can lazy load the components. This will work with offline compilation, does not have security concerns and still allows for offline compilation. @wardbell Could we turn this into a cookbook? As in how do I do |
Will there be an equivalent Dart solution? I don't see how to translate the explained solution to Dart. |
Dart ang JS are identical in the source code hence in the reasoning. |
Anyway, I think this issue will be the biggest stumbling block for many people ... |
I'd like to document. But I don't think i understand the scenarios well enough. Many ways to skin this cat. When the variations are few, IMO, its not a big deal to write a component per variation and use ngSwitch. In my A1 life I only used ngInclude for small variation sets and so I don't miss it in A2 The volume requirements from @tolemac beg for a different kind of approach such as the entity metadata driven ideas in the "Dynamic Forms Cookbook" (see the docs). But that may be too general. I sense that @tolemac would like to write custom screens for each of the 400 entities. That need not imply 800 files; with such small html, inline templates should be fine, at least most of the time. I think the inheritance/mixin issues can be addressed adequately. It will take some more thought and help from this group. I'm noodling it! |
Now that the discussion is veering into "how-do-I-do-this" territory, I think you want to move over to the Angular mailing list. Github issues are really for discussing bugs and feature requests. |
I feel like dynamic components/templates are a prominent enough use case to warrant high level support instead of relying on low-level services (such as the now deprecated DynamicComponentLoader or ViewContainerRef) that don't seem to support:
|
I'm also thinking of this. Never having used angular1 before I don't miss ng-include :-) However, I can't put my finger on it exactly but there are times where I wish there was something like ng-include. For example, ngSwitchWhen is a good example. ngSwitchWhen doesn't support multiple case like a standard switch, some people said you can restructure your switch with an if but that doesn't seem very elegant, you just wish there was a way to reuse that html without having a component. This situation reminds me of the beginning of OO when everyone would turn everything into a class, you would get software with a billion class with just a few lines. Even in OO there are times where it doesn't make sense to have something in a class on it's own, it seems that angular2 is at that point by forcing the use of a component even if another solution might be more elegant. Again, can't put my finger on it yet, and even though it always seem possible to refactor to make the code work using the component approach, sometimes it feels like it doesn't end up with the most elegant, clear and easily maintainable design but just the most componentized solution. |
I also think this deserves further thought by the team, if not for 1.0 then after the 1.0 release. Clearly, dynamic components are a necessity. And yes, it's possible to do this now (http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2/), but it's way too complicated and unintuitive for something this fundamental. It seems like there must be a way to streamline this. |
@darkguy2008 one method of creating mostly dynamic is by using if you have any the questions or issues I havn't addressed then feel free to contact me on the Angular Gitter https://gitter.im/angular/angular with @Toxicable |
@darkguy2008 I was very angry with this subject, but I understood the reasons for the change and I found how to implement the old ng-include in Angular 2/4. Please, read my comments on this thread and you can see how to do. |
@darkguy2008 The most based fact is that you have or don't have a compiler in a browser to be able to compile HTML code with bindings and so on. If you have to have a compiler you have to load it first and then compile HTML templates. Only then your app will run. It is possible to create an abstracted API to have just one line to do it and combine that way even with AOT mode (instead of ^^^ 200) but you can't change the base fact related to the compiler. Or as the second way it is possible to develop some abstracted API and background build processes to create AOT compiled modules and components on a server on-demand based on a user HTML code (taken from CMS). Then there will not be the problem with the compiler and the app is fully AOT compatible without any exceptions. |
@Toxicable right, rethinking implementation approach and architecture is a continuous process and requirement. The best solution I've found is to work with "component inheritance" (which had a lot of bugs) in the beginning) but is much better than other approaches found here. @zoechi If you tell us that angular isn't the right for dynamic UI you are maybe/probably right. But if you take a look out there that's the need for most of the applications I know. Instead of blocking users requests and defending your approach listening to users and thinking about solutions and how the framework could be adapted, extended to be useful for a wider audience is usually the way I know and would expect The excellent angular team is going to have the most performant, most sophisticated framework, but is in the danger to loose their users because of not listening to them |
@KarlXOL he Angular team not listening to their users is in my opinion a completely wrong assumption. As I mentioned above, if a dynamic UI is your main requirement, Angular probably isn't the best choice for you. |
@zoechi think ya tagged the wrong person there :p |
@Toxicable thanks, sorry, fixed |
@zoechi Sad, to hear from you there are "tons of people" complaining about angular. Maybe you should take this is an indicator there might be something "wrong" with your approach on managing framework development and "selling" it to the community. I'd suggest to shift your focus a bit on the user and their needs. It looks like you are obsessed by "Compiler, AOT, ...". Honestly, that's not the top priority for most of us. |
If people have questions, lots of people are prepared to answer them and guide them towards a solution. Just my opinion. I'm not in any way related to Google or the Angular team. |
I am dynamically creating components just fine as long as we include the compiler in the runtime. I don't even mind the few extra lines of code needed to do it. It is possible. So if a "large dynamic UI" is not possible to implement in Angular 2/4 without the compiler, then how does angular team suggest those who wish to Port large dynamic UIs to Angular 2/4? Just don't do it? |
@egucciar take a read up this issue, there are many ways around this issue that preserve the performance of your application. |
@Toxicable thanks for responding. I read the entire thread and thought the gist was all the ways of doing this dynamically which don't involve switch or if statements which aren't really dynamic. Also there is an option to generate on the backend and lazy load. That seemed to be interesting. Was that the option you were thinking? Because the way I read there thread there's no pure front end option which doesn't involve using compiler or if/switch |
@egucciar the one I recommend would be the top half of this here #7596 (comment) |
@egucciar I also have a demo of it working here https://stackblitz.com/edit/angular-dynamic-content-viewer?file=app%2Fapp.module.ts |
@egucciar well I'm not sure if it helps but it solved my ngInclude issue - although I had to compile a component instead, it allowed me to include dynamically-created components and insert them inside a div. So you can do an ngInclude in two steps: 1. Compile your component, 2. Set a placeholder div and paste your component there once it's compiled. I made an article about it here along with sample code: https://medium.com/@dark.guy.2008/compile-for-angular-4-ff800de4a77b @Toxicable although I appreciate your explanation my Angular 4 knowledge isn't as good to understand either the explanation or the sample code you have linked, so I solved it that way :P |
@darkguy2008 If you want help understanding it then jump on the Angular Gitter and I could give you a run down of what that code is doing https://gitter.im/angular/angular |
Yep, I got the dynamic component and template working with the angular two syntax thank to runtime compiler. It's awesome! But if angular team does not recommend to include this in your front end, it is sort of a dead end if I desire to follow in only recommended angular approaches. @Toxicable I'll take a look at this asap. Thanks so much |
@darkguy2008 I can see you added to the DOM directly. We did it a bit differently and it's angular 2 syntax. We leveraged the "view child". I believe some code with that was also posted here. Component factory code is similar thought. This does require compiler :( |
I am receiving external HTML that I am modifying the hrefs to be [routerLinks] on the server side. Since SafeHTML doesn't process or bind, the links do not work. @Toxicable did one of your solutions work for this scenario? Or do I need to include a compiler option for this in order for Angular to process my HTML that contains routerLinks's. I plunkr'd the basic scenario which doesn't work and looking for a solution that could work. http://plnkr.co/edit/2CC7VruA0ffYhtOe9Ndm @ptollena - did you ever solve your external HTML? I believe you had similar issue to what I just described. Thanks |
I am not interested in Dynamically loaded HTML , I am interested in having statically loaded HTML the equivalent to a #include statement or c# razor HTML helper , such that repeatative HTML (with bindings) can be used in multiple places. |
@seanspyder then make a component |
I'm dealing with a complex responsive HTML template, which has a lot of alternative HTML markup based on media queries. That is to say, the Angular component is the same (data, interaction and functionality), but has many gradual steps of presentation as a visual component on screen. For this use case I would want to be able to split up my HTML so I can focus on the various screen sizes of the visual components in my template. This is currently not possible with Angular, and I don't see how I can make components from this, seeing as their inclusion is media-query based. Because of this, I'm forced to deal with a 6 page long jumble of HTML. I don't want to go into the manual dynamic component trickery, I came to Angular to avoid that sort of juggling. Same goes for rewiring component state based on visibility state based on media queries. Currently the only sane way I see is to eject to Webpack and do some pre-processing to include HTML fragments. This too is not acceptable. |
@bbottema ... it looks like you have just one big component. Maybe a composition which includes more elementary components would simplify your design? |
@mlc-mlapis, thanks for the suggestion, but as I said, I don't see how making a component tree based on media queries makes sense (how would you even do that, monitor style changes that are based on media queries?). |
@bbottema Reaction on media query is a common behavior and also officially supported by CDK: https://github.com/angular/material2/tree/master/src/cdk/layout |
@trotyl Interesting indeed, thanks for the link. Still though, this complicates my situation more than it simplifies (I would have to rewrite my components to fit this layout model). I just want to organize my HTML a bit more sanely. |
@bbottema had the same issue, started hostbinding a CSS class to the width of the of a component. I needed to have this also for separate components because I'm building a dynamic grid of windows that can be resized individually and I need each of them to be responsive. In this way you can use this in CSS (using host-context) as well as in the code (because of the binding). In this way it's easier to split up your application into components. Unfortunately you're not using media queries then, but you can reach a similar effect by binding a class to your body element (or main component) for each break point. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
I am very sorry for making dupl of #2753. But after closing this issue on 2 Jul 2015, there are a lot of compelling arguments from community for allowing this feature.
I read this article with statement: It is no longer possible to implement ng-include....
I only want to make sure that:
The text was updated successfully, but these errors were encountered: