AngularJS - Managing URL Changes for Multiple Controls / User Interface

Building an Angular application, I am a fan of using an ng controller and custom directives to structure the application, for example:

<nav ng-controller="NavController"></nav> <date-picker></date-picker> 

I like these templates because they are declarative and very easy to follow - you know exactly where to look for support logic.

On the other hand, using ng-view or even the ui-router plugin (in my opinion) abstracts some functions and makes them difficult to read.

However, my preferred pattern gives me a problem when it comes to responding to changing URLs in an application logically. I would like each part of the user interface to respond appropriately to changes to the URL, but I don't know where to put the code. I suggested that I have two options:

  • Respond to $ location changes separately in each controller or directive
  • Encapsulate this in another class or service that is responsible for listening for URL changes.

I canโ€™t figure out how to do this.

Option one gives me full control, but I can't use the ng-route parsing options, etc. I really need to collapse on my own when it comes to checking URL changes.

With the second option, I cannot refer to any of my controllers, because they are already declared!

In a broader sense, my concern is not to find a solution to this right away, that I should think about things wrong. Is this fundamentally wrong?

EDIT: For the avoidance of doubt, I talk a lot about SPA, and more specifically, this is what I'm trying to do:

 <nav ng-controller="NavController"><!-- more HTML here --></nav> <div ng-controller="VideoController"><!-- more HTML here --></div> <div ng-controller="CommentController" ng-show="Active"><!-- more HTML here --></div> 

Now suppose I go to: "/ video /: key /" - I want the VideoController to pick up the video key and do what it needs to download the video. I want the NavController to highlight which menu item is active, etc.

If I go to "/ video /: videokey / comment" - I want the VideoController to download the video, and the NavController to highlight what is active, and the CommentController to load comments / appearances in the video, etc.

I have no head for this idea - an answer to changing URLs in two controllers, each of which is responsible for a separate part of the user interface in a single-page application.

+6
source share
6 answers

This is not the answer you are looking for, but it is the answer you need to hear (IMO).

Opinions away!

You will spend a lot of time creating a SPA around your own layouts and routing ideas. It would not surprise me if it were possible - if you select events in the corresponding area and ask the child controllers to listen to state change events, you can define different controllers that respond differently to state changes by displaying and hiding their contents, and updating these contents to reflect the current object model (/ things / 1 on things / 2 on things / 2 / edit or something else).

This works pretty much for ui-router, except that instead of embedding top-level html content on main pages, it uses ui-view directives, which are mostly handled by partial and controllers.

At the end of the day, by doing this, you will reproduce about 50% of what ui-router is currently doing. If you're lucky, it will work just like ui-router. If you do not, it will be a funny mistake.

You will have a single-page huuuuuge application that will be very difficult to debug. If you have everything on one top-level html page without templates, you cannot easily separate the problems or decompose the behavior. Some other developer will not be able to monitor the work, and it is difficult to find more subtle errors with incomplete tags. Plus: all the time struggling with the framework could be spent on making your application work.

+4
source

As you suggest using ngRoute, you can simply enter the $rootParams service into your controllers and get all the current parameters. If you also need the current controller selected by ngRoute, you should also enter the $route service. See the example in the ngRoute documentation for more details on how to use these services, or to provide a (minimal) version of your angular code for give you an example based on your use case.

BTW: If you also have different views and / or layouts (for example, not just video) in your SPA, you can use the ngRoute ng-view directive to configure the viewport for all of these different layouts. Thus, each layout can have its own template and layout controller, which can reuse common controllers and directives (for example, for comments). Again, I need more code to give a meaningful example.

+2
source

For what you want to do, I see three options.

  • Use $rootScope to bind your controllers; save URL variables here. When they change, your controllers can respond accordingly. You can use $broadcast and $emit here to send messages, or you can just view the $rootScope variable.
  • Encapsulate your routing in the publish / subscribe service. The service will process your routes, while your controllers will follow any published changes. This can be elegant, depending on the complexity of the behavior you want.
  • Use nested controllers. An external controller will handle your routing; internal controllers, your views.

It sounds like you want to avoid the routing logic in each controller, which is good, but you need to find a way to specify the behavior you want. If I tried to collapse this from scratch, I would prefer that I publish / sign myself, I prefer encapsulating in a provider for something like this (since it is modular and can be easily reused).

However, I agree with the other answers here - it would be much easier to just use ngRoute or uiRouter . By doing this, you can set routes in one place (along route parameters) and use either nested controllers / views or directives. You might consider converting Video and Coments objects to Angular directives.

+1
source

Try angular -ui router. This may be the library you need. Github project: https://github.com/angular-ui/ui-router

0
source

I think you are not talking about SPA, a single page application.

So the question is:

Do you want to use the same $routeProvider for many pages and provide the correct controller for the current page path?

Unfortunately, the URL route path and angleularjs route path are different, and you cannot use the URL route for an AngularJS route route.

To get around, this is my idea.
We can determine the trajectory of the route of corners from an absolute path.

  • In your application, find the current path using $window.location.href or $window.location.pathname

  • Use this path inside your block.

Here is the code and demo: http://plnkr.co/edit/OS38E38J11FeDS1hyHde?p=preview

  angular.module('myApp', ['ngRoute']) .controller('MainController', function($scope) { $scope.pageName = "main page"; }) .controller('Page1Controller', function($scope) { $scope.pageName = "page1"; }) .controller('Page2Controller', function($scope) { $scope.pageName = "page2"; }) .config(function($routeProvider, $windowProvider) { var otherwiseFunc = function() { var absPath = $windowProvider.$get().location.href; console.log('absPath', absPath); var redirectTo = absPath.match(/path1/) ? '/page1' : absPath.match(/path2/) ? '/page2' : '/main'; return { redirectTo: redirectTo } }; $routeProvider .when('/main', {templateUrl: 'partial.html',controller: 'MainController'}) .when('/page1', {templateUrl: 'partial.html',controller: 'Page1Controller' }) .when('/page2', {templateUrl: 'partial.html',controller: 'Page2Controller' }) .otherwise( otherwiseFunc() ); }); 
0
source

Probably the easiest way that will cover all you need is to create a service for handling URLs.

The service will return a set of parameters relevant for each controller, which depends on the URL. For example, it will have the Video.id property to indicate the identifier of the video, Nav.id to indicate the navigation link, etc.

The service itself will be very simple - selecting a URL, dividing it into parameters, and the most difficult part is dividing which parameter is needed for which controller (to create an object, following the rules from the above example).


Example URL: /video/mySupercoolVideo/comment

The service returns something like:

 { video: "mySupercoolVideo", nav: "comment", comments: true // other url-related data here } 

This is a very simple and simple example (navigation and comments seem redundant, and I have not expanded any of the top-level properties, so there are no such things as Video.id , etc.), obviously, you can expand / optimize this a lot.

Each controller will check the status of the URL at the beginning and work according to the response.

If you want, you can also use a shell controller for this, so instead of returning the same data for each controller, you would simply populate one $ rootScope variable with that data.

0
source

Source: https://habr.com/ru/post/975740/


All Articles