Templarian / ui.bootstrap.contextMenu

AngularJS Bootstrap UI Context Menu
MIT License
259 stars 127 forks source link

Delayed rendering #118

Closed RogerMito closed 7 years ago

RogerMito commented 7 years ago

Hello.

Firstly, I would like to congratulate the team for their work.

I was able to solve my problem. In this case, context menu construction parameters are obtained from a database via AJAX calls. Once the information is available, I build a custom html (customHtml). After that, I make the attachment an id for each customHtml (this id is referring to some URLs that I should access after clicking on a context menu item). Through $ li access, I get the id of each element and identify the item that was selected.

I had to do something like: Loop: { For (let x of $ scope.menuOptions) { If (x.link == parseInt ($ li [0] .firstChild.id)) { $ Scope.srcPI = $ sce.trustAsResourceUrl (x.url); Break loop; } } }

However, I still have another problem that is related to context menu rendering. As my data is obtained via AJAX the context-menu policy is invoked before the information is available. Investigating the source code of the library I noticed that it returns a function. I should be able to redo the policy from the instant my data was available.

I thought about using $ rootScope, $ broadcast, and $ scope. $ On to signal the arrival of the data. However, I still have no idea how to adapt the library code to do this.

Would you have any suggestions?

Thank you very much.

josetaira commented 7 years ago

Is the context menu generated each time? If so you can just pre-load it instead of loading it when the user invokes the context menu. This way, when your context menu is invoked, it will already have the data.

Something like:

$scope.menuOptions = [];

$http.get(...).then(function(resp) {
  //... extract data from resp
  $scope.menuOptions = [
     //...AJAX data
   ];
});

EDIT: as of https://github.com/Templarian/ui.bootstrap.contextMenu/commit/950a13f6733cc082deeaf211e57ff445597c7b9d you can now use a promise for the menuOptions

RogerMito commented 7 years ago

Hello @josetaira . I'm trying to do something similar and even implemented a promisse:

$scope.rightClick = function (text, parent, index, idPanel){   
$scope.buffer = angular.copy(text);
        let promisse = monitorService.getExternalLinks($scope.buffer.idVariavel).then(function (response) {
            return response.data;
        });
 $q.when(promisse).then(function (response) {
// $scope.menuOption = response.data --> others operations for mouting context menu
}
}

rightClick send info to the selected item to obtain the new data for $scope.menuOption.

However, the context-menu directive is invoked before the data is available in $scope.menuOption.

follow my html code:

...

I hope you can help me thank you.

josetaira commented 7 years ago

Try this:

$scope.rightClick = function (text, parent, index, idPanel){   
$scope.buffer = angular.copy(text);
var deferred = $q.defer();
// This is the important part
$scope.menuOption = deferred.promise;
let promisse = monitorService.getExternalLinks($scope.buffer.idVariavel).then(function (response) {
            return response.data;
        });
$q.when(promisse).then(function (response) {
// Do something with response data
// After doing something with response data
  deferred.resolve(<the array of objects>);
}
}

This should delay the context menu until the deferred.resolve is executed.

Your HTML code isn't available so I'm not sure how to help you completely.

RogerMito commented 7 years ago

I'm sorry. I forgot to signal the passage HTML... This is my HTML (simplified):

<div  ng-right-click="rightClick(x, $parent.$index, $index)" context-menu="menuOptions">
    [...]
</div>

I'll try what you mentioned.

RogerMito commented 7 years ago

Hello @josetaira! I solve my problem! : D I did not know the $q.defer( ), only $q.all( ) and $q.when( ). Here's my code:



$scope.rightClick = function (text, parent, index, idPanel) {
    var deferred = $q.defer();
    $scope.menuOptions = deferred.promise;
    let promisse = monitorService.getExternalLinks($scope.buffer.idVariavel).then(function (response) {
        return response.data;
    });
    $q.when(promisse).then(function (response) {
        //in this step, the object modeling is performed as expected by the context menu
        deferred.resolve(buildMenuContent());
    })
    function buildMenuContent() {
        let itemsArray = [];
        for (let item of response) {
            customHtml = "<a  href='#' style= 'text-align: left; padding-right: 8px' id =" + item.idLink + ">" + item.nomeLink + "</a>";
            itemsArray.push({
                html: customHtml,
                text: item.nomeLink,
                click: function ($itemScope, $event, modelValue, text, $li) {
                    loop: {
                        for (let x of $scope.menuOptions.$$state.value) {

                            if (x.link === parseInt($li[0].firstChild.id)) {
                                if (item.isModal == false) {
                                    $window.open(x.url, '_blank');
                                }
                                else {
                                    $rootScope.$broadcast('changeUrl');
                                    $('#openModal').modal('show');
                                    $scope.externalUrl = $sce.trustAsResourceUrl(x.url);
                                }

                                break loop;
                            }
                        }
                    }
                },
                link: item.idLink,
                url: item.caminhoLink = item.enviaIdPainel ? item.caminhoLink + panel.painelUsuario : item.caminhoLink
            });
        }
        return itemsArray;
    }
}

This may be useful for other people who need to get the menu options via ajax calls.

Thank you very much.