Need help structuring an Angular app - angularjs

I have a basic angular app, users can post Adverts, now I am working on how to search / filter for adverts. I am currently using a filter like so..
<a data-ng-repeat="advert in filtered = (adverts | filter:filterBySearch) | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit" data-ng-href="#!/adverts/{{advert._id}}" class="list-group-item">
where I have created my own fiter, filterBySearch
I also have a range slider for filtering by a range of prices, and I have all this working with pagination.
My concern is because I have declared <section data-ng-controller="AdvertsController"> at the top of the homepage in order to use the AdvertsController for Advert logic, I am now finding I am putting logic in here around, pagination, the range slider, filtering logic etc. I would like to know how best to split this logic out into their own controllers or whatever it needs.

The controller should not he hadling such complex business logics in itself. It must be used for binding scope elements, handling events, updating states etc. I would suggest pulling your pagination, range slider, filtering logics etc in dedicated angular service and inject the it into your AdvertsController. This way you can also utilize them in any other view/controller you require.
Read more about modularity in AngularJS here

If you have business logic pertaining to elements inside of your tag, then it still makes sense to have all of your code inside of that controller. It might make more sense to rename your Controller to something that better suits your needs.

Related

Angularjs ui-route correct implementation for multiple views

I would like to implement a page like this
I have the following folder structure:
-root/
--root.controller.js
--root.module.js
--root.routes.js
--root.html
--filters/
----filters.controller.js
----filters.module.js
----filters.routes.js
----filters.html
--tableData/
----tableData.controller.js
----tableData.module.js
----tableData.routes.js
----tableData.html
--graph/
----graph.controller.js
----graph.module.js
----graph.routes.js
----graph.html
I would like to know the best approach in order to manage call from each controller in the best way.
I mean, from filters, I can change selection on dropdown or update other fields values, and then I would update data on tabledata. And if I change selection on tabledata I would update graph.
Root url is '/root/{itemId}' and I cannot add some other value on querystring.
How can I manage internal variables and methods?
thanks a lot
From my understanding, it's better to go for events $emit , $broadcast & on to achieve the same.
As I can see, you are having independent controllers with no relationship with most of the the other controllers.
Few suggestions to implement it:
use $rootScope.$emit and $rootScope.on if they controllers have no relationship. Make sure you are removing it manually though (can be ignored if the app is not too heavy but should be kept in mind). This link will be surely helpful . Eg:
If the filter is changed, an event filter-changed will be triggered. The graph.controller and table.controller will be informed and will render the UI accordingly.
Create a messaging service from where the controllers will subscribe and unsubscribe the events. That will keep numbers of events in check. You'll be aware of how many events have actually been created in the application.

Angular sidebar search directive

In my angular application I have a global sidebar navigation directive which among other things provides a global search for the user (with bunch of criteria, not just a text field).
Upon searching I'd like to show a page with the search results.
Now, the sidebar is defined in the main app html, what is the best way of sharing the search results data?
Should the sidebar be in charge of performing the search? If so how do I share it's data to the specific page results?
Or on the other hand, perhaps the specific search results page should be in charge of this data? If so how do I connect it with the sidebar search parameters when performing a search?
Any best practices of this scenario are appreciated.
Steps to make your future bright:
Separate your search module in 3 modules: main, sidebar, results
Translate data between each of them with one major SearchResultsService that will:
a) acquire collection of sidebar filters with true or false for each key (key as name for GET param that will be used for passing to search API of your back-end);
b) serialize or deserialize data depending on results module approach;
c) do some pagination;
d) hold or even cache data if you need (for infinite scroll functionality);
sidebar and results will be views of main (child modules), so you will be able to share main controller methods if needed (noob way)
When I was facing implementation of such module I've used black magic to escape $watch and $on event system. If you are young - then use $on that will allow you to notify each of modules about something important (such pagination change, item selection, etc.) and keep them separated same time.
You are free to place your existing sidebar in main module but I'd moved from directive to view with own controller and template.
Directives are used for reusable items either for pasting functionality. But dat sidebar obviously should be defined as separate part of app (aka module) but not as directive.
P.S. Keep your controllers simple.
Google list:
Multiply satisfection
Your golden chest
Root of AngularJS evil
Angular services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.
https://docs.angularjs.org/guide/services

Do we need multiple controllers to implement routes in angularjs?

There is chance that I might not be able to explain my problem properly. Let me try.
I am developing a single page application using angular. This app basically displays the episodes of an online novel series. There is a navigation bar, which has query menus (Like, latest episode, episode of a particular date, episodes with a particular tag, etc). For each of these queries, i want a separate url.
/latest - should display the latest episode
/tag/:tagname - should return all episodes with that tag.
For all these queries, the resultant view is the same (list of episodes). So I will be using the same partial for all routes.
My question is, Should I actually create a new controller for each query? like, LatestEpisodeController, TagController?
Is there anyway I can use the url to determine what the user wants and run that query from within the same controller?
Ofcourse you can use same controller in routing definition, the question is what is the purpose of that? It will be worse to debug it later, if you have a shared functionality it's better to turn it into a factory or service and then use in controllers.
But the answer is YES, you can use same controllers and implement different behaviour basing on i.e. $location.path()
yes you can use single controller for multiple routing..
you can create different functions in controller and in each function do the according job.
In my case I have created different html page for different url and registered same controller for the html pages and in the html page I have called controller method using ng-init in div portion.
You can use same controller and same views as you wish...
$location can help you to get current path or full url if you want and you can call your service depends on your path...
here I write a little example for you to get the idea
PLUNKER

Dojo: loop with data binding

I'm just starting with Dojo, and I'm really impressed with the amount and quality of all the modules. Coming from AngularJS however, I find the two-way data binding of Dojo's MVC a bit lacking.
Is there really no way to subscribe to a Dojo Object Store, have a loop in a template to iterate over the items in the store and having the view update automagically when items are added/removed? The example tutorial uses dojo/store/Observable to implement this cumbersome logic:
results.observe(function(item, removedIndex, insertedIndex){
// this will be called any time a item is added, removed, and updated
if(removedIndex > -1){
removeRow(removedIndex);
}
if(insertedIndex > -1){
insertRow(item, insertedIndex);
}
}, true);
function insertRow(item, i){ ... }
function removeRow(i){ ... }
In AngularJS you would do something like this:
<li ng-repeat="item in results">
<span>{{item.text}}</span>
</li>
So do I have to choose between Dojo's extensive widget and modules collection and AngularJS's straight-forward templating with two-way data binding?
First of all, congrats on coming over to the Dojo side. Yes AngularJS is extremely convenient for 2 way data bindings, but you'll soon find out that as an application grows more complex, you'll be needing the help of the powerful (and numerous) Dojo / Dijit / Dojox modules.
You are right dojo/Observable currently provides binding via store in Dojo. It can really achieve the same power as AngularJS. Checkout dgrid examples for a demo.
For convenience, a module has been made for binding in a format similar to Angular JS. Its called dbind. It can be used independently currently and will soon be integrated into Dojo's core. You should also check dojox/mvc/Bind

AngularJS pattern for persisting record selection through multiple asynchronous calls?

We're working on CRUD patterns for a fairly large application. One common UI pattern we're using to define a one-to-many relationship where a record is associated by checkbox. The challenge is to persist selections (checked/unchecked) through asynchronous calls (search/sort) that refresh the record list (and the associated ng-model). I'd like to hear from more advanced AngularJS users (I'm a noob) what's considered a best practice for this? Any feedback is appreciated!
EDIT
Here's a working plunk showing how I'd most likely tackle this with my current understanding of Angular. Please let me know if you have a better approach!
I think u could maintain a separate collection of selected names. So the next time you filter the list, you just need to lookup in the collection in order to keep the item selected. That you can do by binding some variable (arrSelected) in the controller or you can create a separate service also.
Have you considered using a filter instead of refetching. Of course this really depends on how many items you plan on having, but I've had success filtering a nested JSON object with around 5000 items.
Here is the full plunker : http://plnkr.co/edit/l4jYgt0LjRoP2H0YuTIT?p=preview
Highlights:
In index.html for your repeat you add | filter
<tr ng-repeat="user in users | filter:userFilter">
In script.js we add the filter function and a $scope variable to hold the filtered letter:
$scope.filteredLetter
$scope.userFilter = function (elem) {
if (elem.name.lastIndexOf($scope.filteredLetter, 0) === 0 || $scope.filteredLetter == '') {
return true;
} else {
return false
}
}
As a bonus I added in ng-class to show which letter was highlighted.
Pretty simple code but this gives you full persistence now even as people change things. You can even experiment now with adding a <input> tag with an ng-model binding to say $scope.filteredName. Then all you need to do is add the JS to the filter to do a deeper filter for part of the name.

Resources