I want to change the uib-dropdown
template dynamically when the user clicks one of its <li>
, just like he could "navigate" within that dropdown.
I tried to make it via templateUrl
, but nor the ng-templates
nor standalone partials can successfully change the dropdown template dynamically, just like this plunkr demonstrates.
My goal is to create a faceted navigation via this dropdown to build query visually, as seen on Fieldbook's Sprint tracker (account required), which is something really like Pure Angular Advanced Searchbox, but I'm having overwhelming issues using this library.
Is this possible to achieve using just AngularJS and angular-bootstrap?
http://plnkr.co/edit/1yLmarsQFDzcLd0e8Afu?p=preview
Based on your plunkr, you should change
<div class="input-group" uib-dropdown auto-close="disabled">
<input type="text" class="form-control" placeholder="Click to start a visual query search..." autocomplete="off" uib-dropdown-toggle/>
<ul class="dropdown-menu" role="menu" ng-if="ctrl.dropdownReady" uib-dropdown-menu template-url="{{ctrl.dropdownTemplateFour}}">
</ul>
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
</button>
</span>
</div>
to
<div class="input-group" uib-dropdown auto-close="disabled" ng-if="ctrl.dropdownReady">
<input type="text" class="form-control" placeholder="Click to start a visual query search..." autocomplete="off" uib-dropdown-toggle/>
<ul class="dropdown-menu" role="menu" uib-dropdown-menu template-url="{{ctrl.dropdownTemplateFour}}">
</ul>
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i>
</button>
</span>
</div>
In which the ng-if="ctrl.dropdownReady"
is moved to the div.input-group
.
And change
vm.dropdownReady = false;
console.log('vm.dropdownReady =', vm.dropdownReady, ' partial = ', partial);
switch (template) {
case 'word':
partial ? vm.dropdownTemplateFour = 'word-dropdown-dom.template.html' : vm.dropdownTemplateThree = 'word-dropdown-dom.html';
break;
case 'main':
partial ? vm.dropdownTemplateFour = 'main-dropdown-dom.template.html' : vm.dropdownTemplateThree = 'main-dropdown-dom.html';
break;
}
vm.dropdownReady = true;
to
vm.dropdownReady = false;
console.log('vm.dropdownReady =', vm.dropdownReady, ' partial = ', partial);
switch (template) {
case 'word':
partial ? vm.dropdownTemplateFour = 'word-dropdown-dom.template.html' : vm.dropdownTemplateThree = 'word-dropdown-dom.html';
break;
case 'main':
partial ? vm.dropdownTemplateFour = 'main-dropdown-dom.template.html' : vm.dropdownTemplateThree = 'main-dropdown-dom.html';
break;
}
$timeout(function(){
vm.dropdownReady = true;
});
Which has a $timeout
wrap the vm.dropdownReady = true;
. And you should inject the $timeout
by hand;
According to the documentation, we can choose the initial state of drop menu with is-open
attr. And we can listen the toggle event with on-toggle
attr. So if we want to keep the menu open after user clicking the input, we should set the attributes of uib-dropdown
like this:
<div class="input-group" uib-dropdown auto-close="disabled" ng-if="ctrl.dropdownReady" is-open="ctrl.open" on-toggle="ctrl.toggled(open)">
And in controller:
vm.toggled = function (open) {
// the parameter `open` is maintained by *angular-ui/bootstrap*
vm.open=open;//we don't need to init the `open` attr, since it's undefined at beginning
}
With these things done, once the menu is open, it doesn't close without user clicking the input again.
Let's check this snippet:
$templateRequest(self.dropdownMenuTemplateUrl)
.then(function(tplContent) {
templateScope = scope.$new();
$compile(tplContent.trim())(templateScope, function(dropdownElement) {
var newEl = dropdownElement;
self.dropdownMenu.replaceWith(newEl);//important
self.dropdownMenu = newEl;
$document.on('keydown', uibDropdownService.keybindFilter);
});
});
The snippet above shows how does angular-ui/bootstrap use the template-url attr to retrive template and take it into effect. It replaces the original ul
element with a newly created element. That's why the uib-dropdown-menu
and template-url
is missing after clicking the ul
. Since they don't exist, you can't change the template-url with angular binding anymore.
The reason executing vm.dropdownReady = true;
immediately after the vm.dropdownReady = false;
doesn't work is that angular have no chance to dectect this change and execute the "ng-if" to actually remove the dom. You must make the toggling of vm.dropdownReady
asynchronous to give angular a chance to achieve this.