I want to display a list of events of very different types that should have different UI logic. Yes, they have common properties (like name, date/time, location etc) but also sets of custom properties that can be simple text, typeahead items, drop down lists etc. Depending on the specific event type (there will be tens of them) I need to handle user input in different ways. For example, on select a typeahead item I want to clear two other fields etc.
I'm gonna display those events using ng-repeat and dynamically load template views depending on the specific event type. These views will have proper controllers that are specific to the business object. I still haven't make it work but please advice me.
Is loading type-related views with controllers inside is a good idea
for this task?
Would directives instead of controllers be better?
Is there a way to dynamically set controller/directive name in the HTML attribute?
Any other advices?
yes
yes, use directives. If you have a base event definition, it is probably best to define an element directive for that and use attribute directives to extend/customize the functionality for different event types.
not exactly, but you can use ng-switch on your list item element.
example:
<li ng-repeat="event in events" ng-switch on="event.type">
<my-event event="event" first-type ng-switch-when="type1"></my-event>
<my-event event="event" second-type ng-switch-when="type2"></my-event>
<my-event event="event" third-type ng-switch-when="type3"></my-event>
<my-event event="event" ng-switch-default></my-event>
</li>
Use require: 'myEvent' in your extending directives to gain access to the base myEvent controller.
Demo
Related
I have a list of fields that are not exclusive. Typically you would use html check boxes and bind each one to a Boolean value in the model. However I have been thrown a curve, to save space the users want all of the items to be presented in a select that allows multiple selections. I know how to create the select itself in HTML however I am not sure the best way to wire that up the model using the 'Angular way'. Is there a better solution than creating something in the controller to "translate" the select result to series of Booleans?
Welcome to SO!
Try using this directive:
https://github.com/amitava82/angular-multiselect
More info on SO here: AngularJS. Bootstrap multiselect without JQuery
I ended up creating a var in scope for the dropdown. Which wasn't too big of a deal as I keep my view model in a var called viewmodel, so it will not post to the server with rest of the view model. Then in my load and save functions I 'boxed' and 'unboxed' the booleans into a string array I fed to and read from the dropdown. little bit of work but it works. I was hoping the AngularJS framework could have handled this lifting for me but whatev.
Too bad you cannot data bind to an option in the select list (selected == true).
In my site I have a case where I show a simple order which I can add/remove items to and pay to close the order.In other case , I just want to show the order without the option to modify it.
What is the best way to do this regarding to reuse the view ?
Should I create a directive which I can configure to not show update actions
or should I create 2 templates (one for each scenario) which bound to the
same controller but each template use only the methods it needs from the controller?
Thx!
You may conditionally close GUI items when your order view is in readonly mode, for example:
<button ng-if="!readonly">Add new item</button>
Of course your controller should have
$scope.readonly=true;
when you are going to display the view without ability to modify it.
I'm working with angular js and there's one thing I didn't fully understand yet. I know what directives are: they are "additional features" that we add to HTML that can be used as elements, attributes, comments or classes and that can change completely the markup there by some other thing rendered by angular or can add functionality with the link function.
That's fine, but when to use directives? I know that if we want to represent on screen some domain specific object then this is one possible candidate for a directive, or when we want to add functionality to some HTML element (like slider functionality to an input) then we use a directive. But what about other cases? What about when we want to manipulate the DOM to, for instance, activate the functionality of a sidebar or thing like that? Directives are used for this to?
How do when know when to use a directive in angular?
I think about directives when I face one of this two scenarios:
Custom control: I need to implement a custom control, that probably I will reuse in other parts of my app or even other projects.
Custom Validations: AngularJS provides a limited set of validations (e.g. ngRequired, RegEx...), but for sure you will need to implement your custom logic validations. I prefer to implement that validations in directives (reuse, SRP, easy to be tested isolated) rather to overload the controller with that logic.
Some directive rules of thumbs:
If you plan on adding the same markup-based functionality more than once, create a directive (but if it's simple enough, just use ng-include).
If you need to modify the way an ng-modeled input field validates, formats, or parses, create a directive that requires ngModel.
If you want to make writing unit tests easier for a specific piece of markup, write a directive.
If you come from a jQuery background and instinctively feel like using $('.jquery-style-selectors') from your controller, instead write a group of directives where the child directive(s) require the parent directive(s) and communicate via the directive controller(s).
Is it possible to modify $scope variables on button click if the button is outside the controller area?
For example:
<input type="button>
<div ng-controller="MeetingsCtrl">
Using classes or IDs to find elements is not how things are typically done in Angular.
A controller is typically defined on the top-level element of each view. If your button belongs to the view managed by MeetingsCtrl, it should be inside the div.
However, maybe your button is actually part of another view, in which case you need two views to interact with each other. This is normally done via services, with each controller injecting the same service. Or you could use events.
Yes it is possible. What you have to do is, create different class/id for both input and div tags.
Then make your div as absolute and input as relative. Problem solved!
Is there a way that I can tell backbone/marionette not to automatically add a the wrapping container tag when rendering a view to a region?
For example, lets say I want to display a list of items. The way I want to do that is by having one composite view looking looks this:
<ul>
</ul>
And then a item view that looks like this:
<li><%= title %></li>
Now I can easily get the same output by changing what the tag used for the auto generated element is however the biggest reason I would not have the tag automatically generated by backbone/marionette is because I want to keep as much html in the template as possible. If for whatever reason I want to change the list to a table, if all the HTML is contained in templates, I only have to change the two template files. The other way would require me to change 2 template files and 2 javascript files (less file I have to change to make a change, the less chance for error). I just like to have that level of separation of concern.
Neither Backbone nor Marionette have built in support for this. But I imagine if you could get this behaviour with a few tweaks.
Backbone.View has a method called _ensureElement that constructs the el from tagName and className if the el is not provided.
You could override _ensureElement to render the template first an then use it's first tag name as the tagName for the view. You'd also need to override Marionette.Renderer.render to strip the template's outer tag.
There maybe a better choice of methods to override to achieve this logic. I would also advise that you provide a flag somewhere to turn this behaviour on selectively so you could mix and match as needed, which would also help in debugging.