I am new to Backbone, and I have found myself writing views which rely on values of the options object to function properly. In other words, my options are mandatory. That doesn't sound right, so I'm wondering if perhaps I'm misusing the options parameter, and if so, what's a better way of doing things?
Dependency injection is a not bad practice at all. It's actually common practice especially dealing with Views. It also makes it easier to unit test your view. So using the options to get some required attributes to build your View is completely OK. Maybe a you could share some examples of what you think is wrong?
Related
I've seen both of the following methods to use a filter in a controller/service:
$filter('myFilter')('myStuffToFilter', myFilterArgument)
myFilterFilter('myStuffToFilter', myFilterArgument)
They work equally well. Which method constitutes best practice?
While this is not a ground-breaking issue, I believe there is a difference and it's worth sharing (as did pkozlowski.opensource in his answer to a related question). Option 2 is better for the following reasons:
Cleaner syntax: It's a little cleaner, more straight forward and avoids the sequential parentheses syntax which is less common.
Provided solution: The myFilterFilter object is not available for code injection by accident. The AngularJS creates these <filtername>Filter objects for all filters (pre-defined and custom) and makes them available to the injector.
Documented solution: The AngularJS documentation recommends this solution in their documentation here.
I would like to know which is preferable in an angularJS app.
in the html, I can have...
a)
<span ng-class="{'car-icon': category === 'CAR' || category === 'SUV','bus-icon': category === 'BUS','bike-icon': category === 'BIKE'}"</span>
or...
b)
<span ng-class="categoryIcon"></span>
where categoryIcon is set in a controller function.
My preference is for b). a) puts logic in the UI which I do not like. I also find it much easier to test controller functions, so another reason for b)
However I'm being told that a) is the way to go because that is what angularJS templating is for. The example is applying CSS styling however I'm getting the same reasoning for setting href's, there is some simple logic required and I'm being asked to do it in the HTML templating vs a controller function.
It's a matter of preference, but I much prefer option b)
<span ng-class="categoryIcon"> with categoryIcon set in the controller.
If you think ahead, what if new categories are added, that html is going to get long, ugly, and error prone. Also, what if you want to use categoryIcon in multiple places in your html in the future. Simply referencing ng-class="categoryIcon" is much better design than copying option a) to multiple places.
I don't know why the other answers here have been down voted, since this is an opinion on best practices and there is no concrete right/wrong answers, but I would prefer solution A in one-off usages, and a solution hinting at B when it has to be repeated in the view.
I tend to think that the view should be able to handle the data model as it sees fit. It's not really business logic that we're talking here, and I don't want to have to jump into the controller code to see what class is being passed.
If you are making use of this conditional all over the place, though, it certainly would make sense to at least create some convenience methods in the controller: isCarSuv(), isBus(), etc. Then the ng-class conditional blocks would be cleaner.
<span ng-class="{'car-icon': isCarSuv(),'bus-icon': isBus(),'bike-icon': isBike()}">
I don't really think a pure B style implementation is the way I would do it.
Just my two cents. Others are sure to disagree.
I always use this variant since it is way cleaner, but i guess this is from developer to developer different
<span ng-class="categoryIcon">
I have a method (the function in the controller, am I terming that correctly?) and view that I want to use in every controller on my site. Is there a way to make the method global across all controllers and the view .ctp file generic as well? I'd rather not have to copy-paste it everywhere.
This seems like something that should be obvious, so if I'm just searching for the wrong terms, let me know.
Thanks
Shared/Common Controller Code:
What you've described is a "Component":
Components are packages of logic that are shared between controllers.
If you find yourself wanting to copy and paste things between
controllers, you might consider wrapping some functionality in a
component.
See: http://book.cakephp.org/2.0/en/controllers/components.html
Shared/Common View Code:
As far as the View is concerned, there are a few options. If you want the entire view, you can just specify which view to render: $this->render('TestView/index');
Or, if you want a small chunk of code, you can try an Element.
All together:
If you find yourself creating a lot of the different "parts" (View, Controller/Component, Model/Behavior)...etc, all for the same general purposes (ie cropping a photo), you could think about creating a Plugin.
Side note:
Side note: Usually, I've heard the functions in Controllers referred to as "actions", and the functions in Models called "methods". They're all really methods (a function within a class/object), but - that's how they're commonly referred to.
You can put the method in AppController and make only one view.
You will use $this->render('/myview.ctp');
It appears that the when multiple modules have factories with the same name, the last one wins. jsfiddle
I've seen posts suggesting the conventions for naming the factories with fooBar, foo2Bar or foo.bar foo2.bar to avoid naming conflicts
However, prefixing each factory with module name seems pretty ugly to me. Is there any other better way, or is there any way to have private services that's only local to the module?
You don't like foobar? Seems like a pretty good convention to me.
However you can 'namespace' your javascript code if you'd like.
http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/
I'm trying to create a directive to allow the user to navigate the page with arrow keys by section. But I also want to be able to have those sections be scattered around the dom, and to have this not break when stuff gets added and removed. I can think of several ways to do this, but none of them are satisfactory:
Create a directive with a controller that lets other directives register themselves (and unregister on $destroy). But this will be out of order if I add something in the middle later. Also, I've tried writing it this way, and it seems like way more code than necessary.
Whenever the user hits an arrow key, make an empty array, and $broadcast an event, with a callback for directives to register themselves on that list. Then, once that list is full, advance or go backwards on it. They (should?) come back in the order they're in on the DOM, but I'm not sure since this way seems crazy and hackish.
Mark things that are 'tabbable' with css, and write this the simple way in jquery, something like this: On a new click event, var all = $('.tabbable'), and then do the obvious with that. But I really don't want to do it that way, because it's not 'the angular' way. Not out of some sense of purity, but because I'm building this as part of a larger library of widgets, and I want this functionality to be accessibly to them.
So, is there any way for me to get the scopes of all directives of a certain type, without resorting to weird hacks, or spreading the logic out all over the place?
This is a good question. +1
First, finding all directives or nodes by type goes against the Angular way. The View is the official record in AngularJS, so directives should say what they do and do what they say. Coding some process somewhere to scan for DOM nodes and act accordingly is problematic for several reasons, not the least of which are separation of concerns and testability.
I'm glad to see you're looking at other options, but I agree that the other options you provided are sub-optimal for the very reasons you mentioned. But I have one more. This is one that I've used for a different application, but that required knowledge of scattered DOM nodes.
First, we create a service to manage the state of this component. It's simple. Let's call it SectionsService. Next, we create a directive to register sections. Let's call that section for simplicity. The section directive registers the DOM node's ID (maybe created programmatically to ensure uniqueness) with the SectionsService during its linking phase. Since the DOM is processed (mostly) in order, the nodes added to the SectionsService will also be in order. So the DOM looks something like this (irrelevant stuff omitted):
<div section>...</div>
<!-- other stuff -->
<div section>...</div>
<!-- other stuff -->
<!-- etc. -->
(Though out of scope here, it would not be very difficult to program it in such a way that the order wouldn't matter, but it'd be based on specifics of your app that I don't know.)
Next, you create your triggers, like an arrow key handler. On these events, you simply tell the SectionService to go to the previous/next node in the list. AngularJS comes with a service called $anchorScroll that can be used to emulate the browser's hash-based positioning we're familiar with. You could obviously also use a jQuery plugin to animate the scrolling if you wanted to.
And that's it! A very simply directive, a fairly simple service, and whatever trigger(s) you need. All told, I'd guess less than 100 lines of code including tests. All components are decoupled and easily testable, but still really quite simple. The view remains The Truth. The Angular Way is preserved.
And there was much rejoicing.
I hope this sets you on the right direction, but of course feel free to ask a follow-up question. We can also talk code specifics too if you'd like; as I said, they wouldn't be very complicated.
AngularJS services are singletons and can be required via dependency injection. You could have your directives require a state manager service and call incrementers/decrementers.
Alternatively, a little easier but more brittle, you could keep an array in $rootScope. It's more idiomatic "angular" (but not by much) than a jquery selector global, but probably not the best route if you're building a widget library.