In my app, I have a menu that is consistent across pages/view, and a sub menu that shows different links (to more nested child pages) for each main page/view. I am unsure how to approach changing the sub menu. For now, I have both the menu and sub menu in the body, as well as an ng-view element.
First I thought I'll make a controller for the sub menu and loop over an array of sub pages to display, updating the array as the main page/view changes. This seems cumbersome and unintuitive, though, as I'd have to keep a list of sub pages for each page in this separate controller, when really, they are part of the main page's/view's logic, no?
Then again, I've read about the angular ui router and its implementation for nested views - should I rather approach the sub menu as a nested view?
I know SO cries to see my actual code, but I am more struggling with how to approach this problem, not with how to implement it. And it seems to me that something like a sub menu changing per page/view must be a common enough problem, that there is good recommendations for how to solve it.
I'm not sure I understand your scenario correctly - I'll assume a situation where there is a top-level navbar where each navbar item has a set of sub-items (a sub navbar). Also, each top-level navbar item represents a distinct functional area and consequently each has their own model. Hopefully that is close to your situation.
Given that, I'd think that you could have a separate controller for each top-level navbar item (i.e., each functional area). Each of these controllers would be a child of your top-level controller, and each might have their own child controllers.
Put another way, it might help you to think of your app in terms of distinct functional areas, and using the MVC pattern for each area. This might make it easier to reason about your app, and easier to write tests, as opposed to using a single controller to represent everything.
I hope that helps..
It's a good question.
I think that for major flow use the route and for inner panels use widgets. create directives that compiles templates.
I built a dynamic widget you can read about it in here
You could use a ngShow directive for each sub-menu, with code to decide whether it should show or not. You would probably need a different function for each sub-menu which may or may not be shown.needs to be hidden.
Related
I am new to Angular in general and starting in earnest with Angular 2, so I want to find out if I'm not thinking about this in the right way yet.
A "panel" is a page of content in my application. I'd like to use a base panel component to provide common UI and functionality to specific panel implementations that derive from it.
I'd like for the base panel component to have templated content that wraps the template provided by the derived component- this would, for instance, provide a standardized header whose content is provided by the derived implementation and allow for the child component to supply the page content itself.
The ultimate goal is to make it as easy as possible for developers to create new panels without having to worry about rendering the common parts, so that consistency can be enforced.
Also, I want for the developer to be able have two-way binding between base variables/properties that are programmatically set from the derived component and the corresponding elements that are rendered by the parent template... (in addition to the elements in their own child template).
Is this doable? Or am I thinking about this in the wrong way... not sure if I'm in an Angular state-of-mind yet.
As I've been working on this, I'm starting to think I may need to adjust to creating reusable components (like PanelHeaderComponent) that the developer would compose within their panel implementation rather than inheriting from a base for common UI... However, I do need for the container for all panels to be centrally managed somehow.
Want to be sure I do this the right way. Thanks!
I believe a valid approach is, like you said in your last paragraphs, to componentize your application.
Basically: Create reusable components for the different parts of your application (ie: Panel Header with Buttons with a certain style)
If you want different panels that will use the same header, you can then reuse that Panel Header in all of your your panels.
It would be analogous regarding buttons, and any other control that you want to use. Define your component, then reuse it everywhere, then reuse the reusable, composite components that you defined.
Important Note: As of now, and as far as I'm aware, there's no Visual Inheritance between components, so in order to simplify your job, you might want to use sass to define the styles and take advantage of #imports in order to DRY.
I have a view with a bootstrap accordion. Navigating to the view, away from the view, and back to the view disables the accordion functionality.
I imagine the problem is that once the HTML is rendered, it isn't fully disposed of on navigate away?
Any solutions?
My fault.
I had made two naming mistakes. First, instead of changing the IDs of the two accordions, I changed the classes. Whoops. Second, two of the tabs IDs overlapped. This allowed the first one to work, the second one to override it, and the first one to break in the process.
The view composition handles this case well.
I would like to replicate Google's home page functionality in Angular, and it's causing me grief. I've gone through the Egghead videos and read the entire API, but there's no particular example for that exact behavior. What I'd like it to do is the following:
user comes to home page, main search bar is present and generic black header bar
user searches for something, and only when he presses "search" does the main search bar disappear, the url changes to mysite.com/q/searchTerm and a new sub-header appears under the black header bar much like with Google's home page, where the main search field is removed and placed in a grayish bar under the main header bar (if you have instant-search off)
the results of the search appear in place of the now gone main search bar, just like with Google, but this part I can handle with routes and views. The layout switch between two identical controllers is what bothers me.
So far what I've tried was:
make a parent controller for both MainCtrl sub controllers, and set its scope.data = {searchHeaderDisplay: false}
have both sub controllers share the same name (MainCtrl) because they share the exact same functionality
make the one in the header bar ng-show="data.searchHeaderDisplay" and the main one ng-hide="data.searchHeaderDisplay" and then try switching the data.searchHeaderDisplay on ng-click of Search Button. This didn't work - no effect was produced.
I'm still coming to terms with AngularJS, so I'm sure it's quite simple, I just need a practical example or two to learn from.
Edit: would it be better to shove the secondary header (with the smaller search field) into a separate view template along with the search results, and just have the root view be the main search field? The documentation is very lax on best practices regarding views and routes, especially routes that will have multiple controllers doing something.
If I understand you correctly, you set scope.data = {searchHeaderDisplay: false} on the parent controller of the two MainCtrl controllers, with the intention to enable the MainCtrl controllers to share the same model data. That's all fine.
Without seeing your code, my guess is that the problem lies in how you switch data.searchHeaderDisplay on ng-click. You might have set data.searchHeaderDisplay at the child scope level (ie. the scopes that corresponds the MainCtrl controllers) when you should have assign the value to their parent scope level. Let me know if you need me to elaborate.
UPDATE:
After taking a look of the provided code, the problem is indeed as what I suspected earlier (above).
mainProductSearch() is what needs to be changed. Instead of scope.data.searchHeaderVisible = true;, you need scope.$parent.data.searchHeaderVisible = true for the reason briefly explained earlier. If the rationale behind is still not clear to you, then you probably need to familiarize yourself with prototypal inheritance chain of AngularJS scope (and/or Javascript object in general). Scope prototypal inheritance an essential part of AngularJS. Here is a great article on the topic.
Instead of an AppCtrl (which is essentially acting like $rootScope), and using $parent (which is a fragile solution because changing the HTML structure could cause this to break -- e.g., you might find you need to use $parent.$parent... if you add an intermediate ng-controller), I suggest a service for storing model data related to your header. Let's call it searchService.
Controllers that need to affect this model can inject the service. This has the additional advantage that the dependencies are clear (vs controller $scope inheritance, where the dependencies are not clear). E.g., when the user presses "search", the controller can call a notification method defined on the service: searchService.newSearchTerm(searchTerm). Now, all views (like the header view) that are watching for changes in the model will notice the change and can update accordingly.
You might consider using ng-view for the main content area of your page.
See also https://stackoverflow.com/a/14619122/215945, where a very similar layout is discussed. In that SO post, a shopping basket with an item count is in the header. The item count needed to be updated by multiple controllers, so we put it into a service.
I'm thinking about the optimal way to structure my Backbone application. The problem is that I have various complex states, each made by some views showing while all the others are hidden.
What is the canonical way to handle this in Backbone? Two things that I've thought are either controlling the state by the router (calling views hide / show methods) or making the views listen for route event.
The problem with the first method is that the router must be aware of all the views existing in the application.
The problem with this second solution is that I have to make all the views listen to all the events and hide for any of them but a couple that make them show.
Thanks for pointing me to a lean solution.
I use a FSM machine to change the state of the application. Each states shows and hides the appropriate view. My views use transition to animate in and out, so changing the state is more complex, then simple show/hide - it animates in and out from one state into another. I have forked https://github.com/fschaefer/Stately.js to fit my needs.
I can share my personal experience with such a problem. I don't know if it's the best solution, but it worked for me.
My problem was even worse because I had several routers and each of them should hide/show views that belong to it. The solution I chose was similar to the first option you consider.
In my router there is an array which holds all existing views. When the state changes and route callback executes all other views are hidden with this simple code view[i].hide() and the proper one is shown. You can make View model and Views collection if you would like to have more control.
I think it's a better solution, because when you add a new route, you don't have to add route events to all views. Moreover, your views stay decoupled from the router, they may even don't know it exists.
I'm starting to learn Backbone.js and can't figure out one thing: In a typical rails app, I have a layout view and a nested view. My layout usually contains navigation links that are processed by rails routing.
How do I do the same with Backbone? I'm using Rails 3.2 and eco templates.
Should I create nested templates in eco?
Should my navigation links be plain html links with a href or should the navigation be event driven?
For example I have a list of categories on the left, and a category items on the right. I want my categories to be shown on every view and the corresponding category items (with a URL in browser corresponding to selected category) too.
Please point me to right direction, because most tutorials on the Web are 'todo' style applications with no navigation at all.
Thank you.
UPDATE
Turns out, my question wasn't clear, so let me narrow it down.
How can the concept of RoR layouts be applied to backbone.js applications?
And I'm curious about two possible ways of navigation:
create
%a{:class => "customers", :href => "#customers"} Customers
handle ".customers click" event in my view
Which way is better?
And I'm curious about two possible ways of navigation:
create %a{:class => "customers", :href => "#customers"} Customers
handle ".customers click" event in my view
Which way is better?
neither is better until you know the specific context in which you are working. they are simply options for achieving your goal and desired functionality.
there are times when both should be used, as well. for example, if you are supporting search engine optimizations and accessibility.
Here are some better questions to ask:
Which of these will be the simplest thing that can get the job done? will it be more code to write the route handler, or the click handler?
Will the route handler tightly couple the functionality to a router, when I don't need that?
Do I really need a route for this link, so that people can bookmark it and come back to it directly?
Will a click handler cause my code to jump through several hoops of calling other objects that aren't directly related, or can I use a simple event to cause the other objects to run?
There isn't a single correct answer to any of these questions. I recommend trying many different ideas when you can. Keep in mind that you will likely change your answer as you develop new features. The answer that you want, today, won't be what you need tomorrow. But that shouldn't stop you from picking an answer now and moving on. Pick one, put it in place, and when you need to change it, change it.