Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Morten Bock 1867 posts 2138 karma points MVP 2x admin c-trib
    Jul 22, 2016 @ 13:30
    Morten Bock
    0

    Adding querystring to RoutPath on custom tree

    I'm building a custom section with a custom tree.

    The tree is sort of a filter of some underlying data. So my tree looks something like this:

    MyTree

    • Tag Group 1
      • Tag 1
      • Tag 2
    • Tag Group 2
      • Tag 3
      • Tag 4

    Now, when I click the "MyTree" root node, I go to a search page like this:

    /umbraco#/mysection/mytree/search/-1

    When I click the "Tag 3" node, I would like it to pass a parameter to that route, like this:

    /umbraco#/mysection/mytree/search/-1?tag=3

    But if I make me tree node like this:

    CreateTreeNode("3", -1, queryStrings, "Tag 3", "icon-tag", false,"mysection/mytree/search/-1?tag=3")
    

    Then the url I get is

    /umbraco#/mysection/mytree/search/-1%3Ftag=3

    Is there any way, from my tree controller, to add a parameter to the routePath, without encoding the "?", so that I can use $routParams.tag in my angular controller?

  • David Brendel 752 posts 2819 karma points c-trib
    Jul 22, 2016 @ 14:42
    David Brendel
    0

    Hi,

    would also be interested in a solution. Had the problem myself and in the end refactored my code as I didn't found a solution.

  • Ian 178 posts 750 karma points
    Jul 22, 2016 @ 20:25
    Ian
    0

    I don't know if this the 'correct' way and I was interested in modifying a key already present but you could try the same method I used recently.

    if (FormDataCollectionExtensions.HasKey(queryStrings, "tree") && string.IsNullOrEmpty(FormDataCollectionExtensions.GetValue<string>(queryStrings, "tree")))
                {
                    Dictionary<string, string> queryStringsDictionary = queryStrings.ToDictionary(x => x.Key, x => (string)x.Value);
                    queryStringsDictionary["tree"] = "topics";
                    queryStrings = new FormDataCollection(queryStringsDictionary);
                }
                ResourcesSectionApiController controller = new ResourcesSectionApiController();
                var topics = controller.GetTopics();
                foreach (var topic in topics)
                {
                    TreeNode node = this.CreateTreeNode(topic.Id.ToString(), "topics", queryStrings, topic.Name, "icon-book-alt-2", false, FormDataCollectionExtensions.GetValue<string>(queryStrings, "application") + StringExtensions.EnsureStartsWith(this.TreeAlias, '/') + "/edit-topic/" + topic.Id);
                    node.NodeType = "topic";
                    nodes.Add(node);
    
                }
    
  • Morten Bock 1867 posts 2138 karma points MVP 2x admin c-trib
    Jul 26, 2016 @ 07:42
    Morten Bock
    0

    Unfortunately, the query string collection modified here is the one sent to the server when asking for the childnodes of that node. It is not the client side angular route of the node.

  • Ian 178 posts 750 karma points
    Jul 26, 2016 @ 20:57
    Ian
    0

    Sorry for the duff reply. I did a little research and what i found seemed to suggest angular doesn't (or isn't in this case going to) support query strings.

    If you fancy doing a bit of route hijacking for angular (and copying can route out of umbraco route.js which i don't like) then a test of this worked to pass the tag value into routeparams.

    'use strict';
    var app = angular.module("umbraco");
    
    
    app.config(function ($routeProvider) {
        var canRoute = function (isRequired) {
    
            return {
                /** Checks that the user is authenticated, then ensures that are requires assets are loaded */
                isAuthenticatedAndReady: function ($q, userService, $route, assetsService, appState) {
                    var deferred = $q.defer();
    
                    //don't need to check if we've redirected to login and we've already checked auth
                    if (!$route.current.params.section
                        && ($route.current.params.check === false || $route.current.params.check === "false")) {
                        deferred.resolve(true);
                        return deferred.promise;
                    }
    
                    userService.isAuthenticated()
                        .then(function () {
    
                            assetsService._loadInitAssets().then(function () {
    
                                //This could be the first time has loaded after the user has logged in, in this case
                                // we need to broadcast the authenticated event - this will be handled by the startup (init)
                                // handler to set/broadcast the ready state
                                var broadcast = appState.getGlobalState("isReady") !== true;
    
                                userService.getCurrentUser({ broadcastEvent: broadcast }).then(function (user) {
                                    //is auth, check if we allow or reject
                                    if (isRequired) {
                                        // U4-5430, Benjamin Howarth
                                        // We need to change the current route params if the user only has access to a single section
                                        // To do this we need to grab the current user's allowed sections, then reject the promise with the correct path.
                                        if (user.allowedSections.indexOf($route.current.params.section) > -1) {
                                            //this will resolve successfully so the route will continue
                                            deferred.resolve(true);
                                        } else {
                                            deferred.reject({ path: "/" + user.allowedSections[0] });
                                        }
                                    }
                                    else {
                                        deferred.reject({ path: "/" });
                                    }
                                });
    
                            });
    
                        }, function () {
                            //not auth, check if we allow or reject
                            if (isRequired) {
                                //the check=false is checked above so that we don't have to make another http call to check
                                //if they are logged in since we already know they are not.
                                deferred.reject({ path: "/login/false" });
                            }
                            else {
                                //this will resolve successfully so the route will continue
                                deferred.resolve(true);
                            }
                        });
                    return deferred.promise;
                }
            };
        };
    
        $routeProvider.when('/mypackagesection/:tree/:method/:id/tag/:tag', {
            //This allows us to dynamically change the template for this route since you cannot inject services into the templateUrl method.
            template: "<div ng-include='templateUrl'></div>",
            //This controller will execute for this route, then we replace the template dynamnically based on the current tree.
            controller: function ($scope, $route, $routeParams, treeService) {
    
                if (!$routeParams.tree || !$routeParams.method) {
                    $scope.templateUrl = "views/common/dashboard.html";
                }
    
                // Here we need to figure out if this route is for a package tree and if so then we need
                // to change it's convention view path to:
                // /App_Plugins/{mypackage}/backoffice/{treetype}/{method}.html
    
                // otherwise if it is a core tree we use the core paths:
                // views/{treetype}/{method}.html
    
                var packageTreeFolder = treeService.getTreePackageFolder($routeParams.tree);
    
                if (packageTreeFolder) {
                    $scope.templateUrl = Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath +
                        "/" + packageTreeFolder +
                        "/backoffice/" + $routeParams.tree + "/" + $routeParams.method + ".html";
                }
                else {
                    $scope.templateUrl = 'views/' + $routeParams.tree + '/' + $routeParams.method + '.html';
                }
    
            },            
            resolve: canRoute(true)
        })        
    })
    
    app.controller(
        "MyPackage.EditItemController",
        function ($scope, $routeParams)
        }
    );
    
  • Morten Bock 1867 posts 2138 karma points MVP 2x admin c-trib
    Jul 28, 2016 @ 07:34
    Morten Bock
    100

    I've "solved" it for now by simply adding a redirecting controller:

    angular.module("umbraco").controller("Foo.FoorByTagController",
        function($scope, $routeParams, $location, notificationsService, navigationService) {
    
            // This controller is basically just a way to generate the correct search url, and redirect to it.
            $location.search("tag", $routeParams.id);
            $location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + "search" + "/" + "-1");
            $location.replace();
        });
    

    Angular does support this, so it looks more like the Umbraco API was not built for allowing to add them to routePaths from the server.

    Thanks for the example. but I think route hijacking seems a bit much just for this relatively simple task.

  • Ian 178 posts 750 karma points
    Jul 28, 2016 @ 08:04
    Ian
    1

    I saw location.search but thought you needed a query string for it to work, didnt know you could search within a route parameter. Glad you found your workaround

Please Sign in or register to post replies

Write your reply to:

Draft