How to Manage Changing of Views? - javascript

Should I use a router to manage changing of views? Currently, I'm using a 'parent' view to handle 'child' view management.
I have multiple 'child' views within a single parent. Child views/pages are changed by clicking links, which also modifies the URL. The changing of the displayed view is handled by the parent view -- NOT a router. The router in question has nothing of value coded, I created the 'dummy' router so I could use Backbone.history

I suppose you searching for some sort of validation that this is a proper way to construct your application. From the limited information you've given, it's hard to say, and even if you did provide some code, your question might not be definitively answerable, either.
So, let me just put it this way. I don't think there is any flaw in creating Backbone.js views that are composed of other views. I do think there's something wrong if you're putting everything related to view changing in the router--unless you're giving some sort of high level description there--like passing in views the parent view should show/attach events to/something else.
Another point. How are the child views related? Might some of them have a common (high-level) interface? Or does your parent view wrap disparate things, like a search form and some grids and labels? Or both? Is there some chance that this parent view might be useful on another page, or is it just going to manage this particular pages views, etc. All this matters.
I suppose there might even a reason to question as to whether or not your parent view should strictly extend from Backbone.View or should have some other sort of "base" class. But if it works and has some reasonable connection to being a "view" I wouldn't bother asking that question. As Jeff Attwood has said, "meta is murder". At some point these kinds of discussions become impractical, and when there are still important issues to be fixed or implemented, it's best to leave reasonable solutions be.
My thinking is if you are using the router to control and delegate things to the parent view, and let the parent view do it's things with it's child views, you probably fine.
You might want to consider passing in the child views through parent view's constructor in the router, though. It's often better, but not always better, to have a separate thing determine the composition of an object than to let the object create it's composition itself. But always go for transparency as well. Sometimes the freedom you get with dependency injection isn't worth the obtuseness of abstraction your code; especially if you're not quite sure what you're doing. Figure out what you're doing, then consider the abstractions you may not have thought of.
If you want to know if you are doing things consistent with the community's ways of doing certain things, you probably ought to go to the backbone.js Google discussion group and review or ask questions the questions there as well.

Related

Vuejs: distribute code across multiple components or everything into a single component?

So I've played a lot with Vue, and now that my app has become large, I am having doubts about how to organize it.
I understand components and that they make sense when you need to re-use them many time on the same page, for example, a "custom select box" component, that will likely be needed in many places.
But what about components that will only have once instance? Example: a administration dashboard interface that has 3 areas: a sidebar with some navigation, a main area with stuff you can edit, based on what is selected in the navigation, another sidebar with stuff related to the main area. Do all these need to be separate components? Because I don't see any benefit of doing that if there is only one instance of each on the page. On the other side, if I stuff all the code in a single "app" component, I could simplify some of the code (less variables)
Summary - typical reasons for using components:
Maintainability.
Rendering performance via component boundaries.
Loading performance via chunking.
If you find that using fewer components improves maintainability then that's fine. It may well be the correct design for your application.
Verbose version below.
The primary reason for using components is to improve maintainability.
Components that are reused in many places such as a select-box are obviously easier to maintain than repeating the same code over and over. However, it is worth considering why that is. It's not just that duplication makes it more difficult to make a change to all of the select-boxes. The other key benefit of using a component is that the extra level of abstraction can reduce mental overhead.
Let's say someone trying to maintain the code sees something like this (pseudo-code):
<select-box :some-prop="blah">
<select-box-option v-for="something" />
</select-box>
Immediately it's clear that this is a select-box. All the gory implementation details of the select-box are hidden away and we don't need to worry about them. By looking at the props, child components and events we can quickly deduce what data goes back-and-forth between the parent component and the select-box. This is just separation of concerns.
This benefit also applies to components that aren't reused. Let's take the sidebar example. We might see this in the template for our main component:
<nav-sidebar #navigate="onNavigate" />
The component's name allows us to quickly identify it as the sidebar. If our current task doesn't involve the sidebar then we can just skip over that bit of the template. As the code has been moved off to a different file we have no difficulty establishing which bits of the code are part of the sidebar and which bits aren't.
In this example the nav-sidebar doesn't have any props and only has a single event. From that we can start to draw some conclusions about how these components interact. It would seem that the nav-sidebar doesn't need anything passed from the main component, it could quite happily live stand-alone. If we need to debug a problem with data flowing the other way we'd almost certainly start with onNavigate.
We couldn't start making deductions like these anything like as quickly if everything was mangled together into one, big component.
Of course it could be that our deductions are wrong. It could be that the nav-sidebar does some horrible things involving $parent to grab data from its parent component. However, that just illustrates why using such techniques is considered bad practice. Maintainable code should allow developers to jump to reasonable conclusions based on the abstractions that appear to be in place.
But it is possible to go too far the other way.
A good abstraction allows you to free up some mental capacity by hiding details behind a label. A poor abstraction adds mental overhead by hiding the code you want to see behind some indirection. Add to that the difficulty of naming things and the burden of extra glue code and you may well be better off just ditching the extra layers and keeping everything inline.
The other thing that can go wrong is splitting components up in the wrong way. Separating concerns requires clean partitions of those concerns. Chop things up slightly differently and you end up with a single concern being spread across multiple components and the resulting mess is typically worse than if you hadn't bothered splitting things up at all.
Vue allows you to split up your JavaScript code in a number of ways, components being just one. Separate .js files, plugins, filters, Vuex, mixins, etc.. There are several options available to you.
Templates, on the other hand, can only really be split up by using components. If you want to break a huge template down into more manageable chunks then components are really the only way to go.
This brings us to another key reason for using components.
A template is compiled down into a render function. When that render function is run it registers reactive dependencies, just like a computed property. If any of those dependencies changes it will trigger a re-render. That runs the whole render function again. Even if that doesn't result in any changes to the DOM it will require the generation of all the relevant VNodes and the diffing algorithm will need to check all of them.
Component boundaries are also rendering boundaries. Each component makes its own decision about whether or not to render based on whether its dependencies have changed.
So, taking the nav-sidebar example, let's say something changes in the nav-sidebar so that it needs a rendering update. If the nav-sidebar is a separate component then it just needs to run the template/render function for that component. If instead we bundle all the nav-sidebar code into the main template then we'll have to re-render everything.
Vue also has support for lazily loaded components as a way to reduce the initial load time of the page. The idea is that many applications have large sections, such as admin interfaces, that aren't relevant to most users. Rather than incurring the overhead of downloading all of those components you can split the components into chunks and download the chunks when they're needed. This is usually implemented via the Vue router configuration.
Chunking aside, the typical way to use the router is to have separate components for the different pages. While in theory it is possible to use the same component for all routes that is unlikely to lead to something more maintainable. I would add that the definition of 'page' is a little fuzzy here but in most applications it's clear what constitutes a different page, resulting in a different component.
No tome on creating code monoliths would be complete without some mention of testing. Unit testing should be thought of as a form of reuse and a particularly extreme form at that. Tests have an unrelenting knack for exposing the mess of spaghetti that hides behind what you thought was a nice, clean design. I'm not going to pontificate on testing but suffice it to say that you won't be able to write unit tests unless you split things into suitable units.
Another key feature of a component is that it has its own set of properties. Its own data and its own computed properties. This sounds obvious but it gains significance when you consider looping via v-for.
<div v-for="item in items">...</div>
The example above uses inline elements instead of components. Any state can only live on the parent. That state needs to be held for each loop item, so we may end up with multiple arrays holding different aspects of the state. Computed properties are similarly difficult to implement when working with loops. We typically end up using methods instead:
<div v-for="item in items" :class="getClassesFor(item)">...</div>
Now consider the component version:
<my-component v-for="item in items" :item="item" />
Each my-component can hold its own state. Let's say, for example, that my-component has expand/collapse functionality. That can now be stored in a local data property within each instance. Likewise each instance will have its own computed properties.
Arguably this is just reuse as the v-for creates multiple instances. However, given we're specifically introducing a new component just to provide a form of property scope, I think it warrants a special mention.
I personally like to have 3 types of components.
Reusable system component. These are used for generic layouts, custom buttons, custom select box ... They are meant to be reused multiple times in the code and be very versatile.
Page/View component. The route usually routes to a specific component. This component is some kind of assembly of multiple components. The distinction allows to quickly identify the "page" of the application.
Logical division. These are the hardest to find. I tend to isolate things that are not related to each other. For instance, a footer may not be reuse but a modification in the footer should concern only the footer. Other examples are the navbar, the menu, each section of an admin. These components should be reusable as much as possible but sometimes they will be specific.
Another example: A comment system. A "comment" would be a component of type 3. A "comment thread" display would be another component of type 3 that use the "comment" component. A page would exist for the subject of a comments thread and would be of type 2.
Note that each component of type 3 and 2 may use other components of other types.
If I want to change the display arrangement of the comment thread I only have to change the "comment thread" component.
Vue components uses not only for re-use. You may split components into logical blocks. SPA for example. You can create grid based on vue components.
Here is the reason why you need to split codes even it is used only once.
With hundreds or thousands of lines of code, it's no question that
splitting code in different files can help make it more manageable.
Although, this can quickly turn into a complicated mess if the
splitting isn't thought out beforehand.
The more you split codes, the clearer it becomes.
It does not only work for Vue JS but also works for almost programming languages.

Should I use <page type="list"> or <listpage> in angular2?

I'm getting started with angular2 and wanted to create a todo-list web app. The UI should consist of two pages (=components) which get slide in/out via JavaScript.
The first one shows all todos in a vertical list and the other one shows additional details when a todo item from the list is clicked.
I'm now asking myself, what's the right way in angular2 to declare the page components?
Should I build a generic component like this?
<page type="list"></page>
<page type="detail"></page>
Or should I create a new component for each page?
<listpage></listpage>
<detailpage></detailpage>
In general, without knowing more details, my gut sense would be that the latter would be more appropriate, i.e. create a new component for each page.
You require two fundamentally distinct types of entities:
a collection and
a single item from that collection.
The first solution that you propose, i.e. a generic component, would be more suitable to multiple entities that all share some basic underlying structure but differ in some (but not all) details, e.g., two different collection views that both list all items but format those items in two different ways. To force that strategy onto your use case would require your generic page component to have no universally shared structure: what template or logic would you share between a todo-list collection and a single todo-item from that collection? Everything would depend on the value of the type attribute. Then what meaning would page have? Essentially nothing.
Your latter suggestion, i.e. having two distinct components for these two different entities, seems more in the true spirit of how angular components are meant to be used.
I suppose one could argue that a more generic page component/view could have some valuable structure that persists for both the list view and the detail view, e.g. main title, navigation links, user info, etc. However, even if you implemented that, I think you'd want to eventually create separate (more deeply nested?) components for the whole list versus for an individual item, which eventually comes back around to implementing your latter suggestion.
I think a useful model is the example code provided on the official Angular2 web site. I could point to several different examples, but I think the clearest parallel to your situation is in the "Advanced Documentation" section, under the "Routing & Navigation" heading. There they provide code that separates components as follows:
hero-list.component: This would seem to parallel your listpage.
hero-detail.component: This would seem to parallel your detailpage.
Clearly they've separated out these two parts of the app into distinct components.
This sort of strategy decision may also depend on the size/complexity of your "entities". If your "list" and "detail" views were both extremely simple, I suppose you could distinguish between them within a single component (e.g. page), just using an attribute (e.g. type). However, in a todo app, I can't imagine either a list view or a detail view being extremely simple. Thus trying to squash both into a single page component would make the component too complex.

Backbonejs, Event Aggregation and Instantiating Views [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
tl;dr
To what extent is the Event Aggregator pattern duplicating what Backbone.Router already does? Wouldn't it be better if Views didn't communicate with each other, even with events?
The trouble
I'm having a conceptual problem with the use of an Event Aggregrator in a Backbone application. My very basic implementation is derived from Derick Bailey's post about it.. I'm using it in Requirejs and I just define a module that extends Backbone.Events and require it in the modules where I need it.
A bit of background: The problem I was trying to solve in the first place was how best to handle transitions between views in my app. Especially automated transitions. It was clear from my reading that two obvious methods were discouraged:
Manually firing a navigation callback on the router with something likerouter.navigate("login", { trigger: true })
Manipulating the browser window.location.replace("/#login") and thus triggering the relevant routing callback.
As far as I can tell, the main objection to both these methods is a loss of the proper separation of concerns. As I can certainly see the value in avoiding Views having to know too much about each other, I looked about for a better way and found the Event Aggregator.
The problem I'm facing with the Event Aggregator, though, is made quite obvious from Derick Bailey's example on his blog post. The views that respond to the events are already instantiated. Any view that is not already instantiated will naturally not respond to any events. So if, for example, I want an event to instantiate a new View as a result of some logic, I either:
Instantiate a new instance inside the current View. In this case I lose most of the advantage of the approach, because now my Views need to know about each other again.
OR
Create some kind of central event-handler that instantiates new Views based on specific events. Which sounds a lot like the original Backbone Router to me. It seems like I could just separate the logic for each Router callback into various Controllers and I'd have the same clarity.
My second problem is perhaps more general. I feel like the Event Aggregator encourages active inter-communication between Views: admittedly in a decoupled way. Ideally though I'd like to keep that to a minimum. Really I want my user to perform fairly self-contained actions within a defined area and then transition to a new area. Am I being naive, in hoping to sustain that?
I feel like I must be missing something obvious, but right now it feels like the Event Aggregator solves the problem of inter-View communication (which I'm not sure I want), but ends up replicating the Router with regard to View management. The problem I have with that is that I'll have two Event systems acting in parallel.
What I'm really looking for is a sensible, reasonably lightweight pattern for handling the instantiation of Views using the Event Aggregator. I know I could look into Marionette, but I'd prefer to understand this on my own terms first, before diving into another Framework.
Oh backbone, confusing as ever. Everyone still has differing opinions on how a good application should work.
So here's my opinion.
For your first problem, have you considered just using an anchor tag in one of your templates?
Login
For your second problem, I'd take a page from other frameworks. Before our company switched away from backbone/marionette we tried to adopt the flux (redux) architecture on top of backbone. It has worked out pretty well for some applications that stayed on backbone.
Adopting that architecture just meant defining some best practices. I think the following rules could work for you:
The event aggregator will be the only thing that can fire route changes directly.
At minimum 2 levels of views (or objects) are needed for any page.
The top most views is called a "smart" or "highly coupled" view (or object). It will allow you to hook into the event aggregator and then pass data or callbacks downward. They can represent layouts or can be mostly devoid of style and just transform event aggregator callbacks to something the generic views can work with.
The 2nd level and below should be designed in a decoupled way. We can call them "generic" views, and they can accept handlers as arguments. This is how they communicates with the outside world.
This means, views have APIs and smart views need to adhere to those APIs.
Quick Example:
function init() {
// this level is highly coupled, and knows about the events
// that will occur
var aggregator = new Backbone.Events();
aggregator.on('gotoLogin', function() {
router.navigate("login", { trigger: true });
})
function gotoLogin() {
aggregator.trigger('gotoLogin');
}
// the Todo class is generic, and defines an API that expects
// a gotoLogin callback
new Todo({
el: '.js-todo',
gotoLogin: gotoLogin,
});
// the Header class is generic, and it also expects
// some way to navigate to the login screen.
new Header({
el: '.js-header',
gotoLogin: gotoLogin,
});
}
If you are building your application as some sort of single page app. This will cause you to nest views, which isn't the end of the world, but it does become tricky with backbone, but is still doable. In fact, you may be able to automate creation of child views (see marionette). I bring this up because it seems vaguely related to the original question around de-coupling. I think the nested view problem in backbone is particularly problematic.
I believe people over-emphasize reusable code and decoupling. Honestly, there needs to be some amount of coupling. Finding an acceptable level is difficult. Defining it when everyone using backbone has differing thoughts on it, is very difficult. My recommendation is that you and your team should figure out a system that works well for you in backbone land and stick to it otherwise chaos will surely ensue.

EmberJS - Calling components methods from outside with a couple solutions (call for discussion)

The following is from an issue I posted on EmberJS GitHub, but Stack Overflow is better suited for a discussion than GitHub.
I am building a few complex components at the moment including composite components and I hit a roadblock with the extreme isolation components live in.
There are several cases where I don't need the components to trigger an action on a controller, but where a controller needs to trigger a behaviour change on the component.
Problems is that the components don't know about the controller and the controller is not creating the components either: they are defined in a template.
I kind of solved the problem by subclassing the Ember.Component class to offer a way for messages to get through components.
The new component subclass breaks the on purpose isolation of components that shouldn't know about the outer controller.
The 2 less invasive options I found to make component methods calls from outside are:
Cache component / name of instance pairs in a global array like
App.components, then call a component method with
App.components['name'].method()
Trigger events from outside, register and handle them in the
components. However in that case I am passing an eventSource object
to the component, often a controller like so: {{my-component
eventSource=controller}}
My question is about how could we solve this problem in the most elegant and less invasive way possible for components ?
For achieving composite components, using the components like lego pieces, it seems impossible to me at the moment to see how we can achieve that goal without breaking the components isolation.
Any input, ideas, solutions, discussion is very welcome.
Note: By the way, the first method that breaks the component isolation is inspired by the work done on the ember-bootstrap components: https://github.com/ember-addons/bootstrap-for-ember
The author had to solve the same problem of being capable of triggering methods inside the components from outside.
Another note: Just for the record, another way to access a component is to use Ember.View.views['name'] where name is a view name you gave to your component. However I feel dirty to make such calls, even more from a controller.
In general, I would try to solve this by binding properties to your component, which could then change according to computed properties or observers based on those properties.
For instance, instead of trying to call a method like deactivate on a component, bind a property such as active to a property in the template:
{{my-component active=formEnabled}}
I'm hesitant to recommend passing an eventSource to components as a general solution (like your {{my-component eventSource=controller}} example). I imagine this could work with a class or mixin that just emits specific events and is tightly coupled with your component, but I'm struggling to come up with a use case that justifies this approach.

Where should I use templating, and where should I generate view objects programmatically?

I am using Backbone.js for an applciation involving a lot of different views, some nesting other views, and these other views could further nest other views.
Also view presentation depends on certain attributes in the model, for instance, some content is only shown if the user has been authenticated, or another type of an if-check
Coming from the world of Adobe Flex, I am used to declaring my views almost completely using markup, even deeply nested, or composite ones. Flex makes component declaration in markup a piece of cake.
I was kinda hoping that I could achieve the same kind of separation between the pure view presentation and the view logic in Backbone, but so far I've been struggling with that.
The reason for this is that in no way can I manage to declare a composite view using templates only. Thus, I have to resort to using BB's render() method to instantiate subviews and append them to the parent. This is OK ... but if the views get really granular, declaring them using JS is an overkill, because I literally end up appending pure HTML strings, which is a complete mess. This means that it is much better to use templating for those ones, and then just render the template instead of doing all the stuff using JS.
Using both approaches simply breaks any consistency in the application, but I push myself to be OK with it, because I've read a lot of (even professionally written) Backbone code, and I 've seen other people struggling with the same thing.
If I cannot avoid this separation of rendering approaches, then at least I will have to put any certain boundaries of which views should be rendered with a template, and which not, or just partially. The question is what will those criteria be.
My methodology is to have all markup contained in templates.
My conception of Backbone Views is that they are actually Controllers. If you consider a Controller in a more traditional web app framework, their job is to receive events, marshal models, fetch and render templates, passing in models, and to return the resulting output.
In Backbone, the Views are the elements responsible for this task. But, instead of http being in input/output medium, the DOM is the input/output medium.
So, I consider Views to be controllers for a specific area of UI on the screen. They listen for events, marshal models, fetch and render templates, and modify the DOM as a result.
The decision of when to go to the trouble of generating a sub-view vs. perhaps rendering a template in a loop, is fairly loose for me.
If it has the possibility of being used in multiple views, I'll make a View out of it.
If it has any events or user interactions which affect itself, but not really anything in the "parent" object I'll make a view out of it.
If it has any real logic, I'll make a view out of it.
If its a related model, or collection, I'll make a view out of it.
But, in any of these cases, the view does not directly generate HTML - I'll always store the markup in a template.

Categories