ng-grid hiding bootstrap styled dropdowns - angularjs

I am upgrading a table form. Each row in the table has several elements, including two drop downs in specific columns for each row. I have upgraded the table to ng-grid and upgraded the drop-downs from plain select widgets to styled bootstrap drop-down elements to match the others on the site. The essential problem I am having is that the CSS layout of ng-grid causes the actual drop down menu to be put behind the cell below, and so not visible. Examining the elements shows that they are actually being rendered, have proper height, width and content, but are merely displayed behind the content in the other cell. I have tried disabling the CSS overflow: hidden on the desired cells, but it seems this property is also set for the entire grid and turning it off at that level totally breaks the grid layout. I have a working workaround, but it makes me want to take a shower and I am sure there is a more elegant way to do this:
1) put a cell template in for just the visible part, including an ng-click call passing the column (Coffeescript):
{field: "type",
displayName: "Type",
width: 155,
original_width: 155,
pinned: false,
cellClass: "type_col",
headerClass: "type_col",
cellTemplate: """<div ng-click="editor.activeCol(col)" class="btn-group">
<button ng-show="row.entity[col.field]" style="width: 125px"
class="btn dropdown-toggle blk-txt" href="#">
{{row.entity[col.field]}}</button><button class="btn">
<span class="caret"></span></button></div>"""
},
2) Put a select row callback to a different method:
multiSelect: false,
enableRowSelection: true,
afterSelectionChange: angular.bind(#, selectFunc),
3) Have a totally separate angular template of the drop-down options that is classed to always be shown open for bootstrap, but has both a ng-show and ng-style elements to allow my code to change its visibility and exact location:
<div ng-show="editor.utilization" ng-style="editor.dropdown_style">
<div class="btn-group editor-widget open">
<ul class="dropdown-menu">
<li ng-click="editor.selectUtil('heavy')">Heavy</li>
<li ng-click="editor.selectUtil('medium')">Medium</li>
<li ng-click="editor.selectUtil('light')">Light</li>
</ul>
</div>
</div>
When a user clicks on the (apparent) drop down, the following happens:
1) ng-click event delivers the column to the class, this is stored
2) row select (afterSelectionChange) callback triggers with the row and is able to get the column from the previous call, with both the row and column we now know the actual cell
3) The exact screen position of the cell in question is grabbed and the drop-down selections template is made visible directly below the clicked cell, making the illusion of a normal drop-down operation.
This is a long explanation, but wanted to give the background of what I have tried, to show that I am looking for a simpler (hopefully MUCH simpler) way to just include styled bootstrap drop-down widgets in ng-grid cells. The entire thrust of this project is to style and beautify already working forms so solutions that work only by cutting style for pure functionality don't really serve the purpose.

This is how I solved it. I have a cell in the ng-grid and in the cell i have a glyphicon arrow down. When I click it I want the dropdown toggle to show. With the CSS I got what I wanted. However, I have many cells with arrows and thus I had to change the css-style "left" dynamically. I do this with my javascript.
Hope it helps!
Cell Template:
<div class="ngCellText" ng-class="col.colIndex()" class="dropdown">
<span ng-cell-text>{{row.getProperty(col.field)}}</span>
<a class="dropdown-toggle" ng-click="setXchords($event)">
<i class="glyphicon glyphicon-chevron-down"></i>
</a>
<ul class="dropdown-menu">
<li ng-repeat="choice in editableItems">
<a>{{choice}}</a>
</li>
</ul>
</div>
CSS:
.dropdown-menu {
position: fixed;
top: inherit;
left: 85px;
}
JavaScript:
$scope.setXchords = function(e) {
var elem = angular.element(e.currentTarget);
$(elem).next().css('left', e.clientX).css('top', e.clientY);
};

In order to show regular dropdowns, I added this css:
.ngCell { overflow: visible; }
In order to get multiselects to appear, I needed to add a class (I used "field-multiselect") to an editableCellTemplate and then add the following css to the class:
.field-multiselect {
position: relative;
overflow: visible;
z-index: 888; }
This worked for me! (Finally, after quite a bit of trial and error!)

Related

Properly toggle a hidden table to visible with angular-datatables?

I have 2 tables, one displayed, the other one hidden:
<div ng-show="displayed('active')" ng-controller="DataTablesCtrlA as datatables">
<table datatable="" dt-columns="datatables.dtColumns" dt-options="datatables.dtOptions" class="display"></table>
</div>
<div ng-show="displayed('retired')" ng-controller="DataTablesCtrlB as datatables">
<table datatable="" dt-columns="datatables.dtColumns" dt-options="datatables.dtOptions" class="display"></table>
</div>
I have a toggle which controls the visibility of the tables, when button A is clicked, then table A is displayed and table B get hidden and vice-versa.
The issue I am facing is that when table B get displayed, the table header is not properly expanded. This is known and well explained on DataTables documention here.
Below a screenshot of the issue:
So I am using columns.adjust() like so:
In the View template:
<div class="btn-group">
<button ng-click="setDisplayed('active')"
ng-class="{active: displayed('active')}" class="btn btn-default">Active</button>
<button id="btn-retired" ng-click="setDisplayed('retired')"
ng-class="{active: displayed('retired')}" class="btn btn-default">Retired</button>
</div>
In the View controller:
//...
this.setDisplayed = function(toDisplay){
this.displayed = toDisplay;
$.fn.dataTable.tables( {visible: true, api: true} ).columns.adjust().draw();
};
//...
The issue I am facing is that table B is still hidden when setDisplayed get called and the header stay "unexpanded".
Is there a clean way to solve this problem ?
One solution I have in mind would be to listen for changes on the table display style attribute and call colums.adjust() in the event handler. But this would require to change the directive link property.

How to make Angular UI Grid row editable when button is clicked

I am using angular ui grid.
I have edit button showing for each row as last column. I want to change row to edit mode when edit button clicked.
Appreciated if someone can guide me.
{
field: 'edit',
displayName: '',
enableFiltering: false,
enableSorting: false,
width: '5%'
},
Right now i have made it editable for each cell individually using the following line
<div class="grid testGrid" ui-grid="GridOptions" ui-grid-edit ui-grid-row-edit style="width: 100%;"></div>
The only way to do this in ui-grid, as for now, is to avoid using ui-grid-edit and implementing some custom templates with ng-ifs conditions inside.
I built this plunker as a starting step, there you can see only one button, but you can simply put a similar logic inside your edit button.

Dojo / Dijit Layouts without Non-Semantic HTML

I'm new to dojo/dijit, coming from a Backbone/Marionette background.
Right now I'm working with dijit's layout system, but I'm kinda shocked by the amount of non-semantic html in the examples needed to get it moving. For example, an accordion (from http://dojotoolkit.org/reference-guide/1.9/dijit/layout/ContentPane.html):
<div data-dojo-type="dijit/layout/AccordionContainer" style="width: 200px; height: 95%; margin: 0 auto;">
<div data-dojo-type="dijit/layout/AccordionPane" title="pane #1">accordion pane #1</div>
<div data-dojo-type="dijit/layout/AccordionPane" title="pane #2">accordion pane #2</div>
<div data-dojo-type="dijit/layout/AccordionPane" title="pane #3">accordion pane #3</div>
</div>
Is there a way to do this without having to add all that into the HTML? Specifically, I'm trying to find the equivalent of 'regions' in dijit layout, so I can include a template for a layout and place views in and out of that easily.
you can create content panes programmatically as in this accordion container example. (AccordionPane is deprecate, just use ContentPane instead)
var accordion = new AccordionContainer({
style: "width: 200px; height: 100%;"
}).placeAt(document.body);
var content = new ContentPane({
title: "content1",
style:"height:100px"
});
accordion.addChild(content);
accordion.startup();
if you need to use regions, bordercontainer's design property gives you that as in this example. you can put an accordioncontainer in one of the content panes there...

How to disable content based on checkbox in AngularJS/Bootstrap3

I am creating a form where the user can configure a recurring event, so there are a large number of controls. At the top is a checkbox to enable/disable the schedule.
How can I disable, but not hide, the entire section based on the checkbox? If it is checked, the user should be able to make modifications to the schedule. If it is not checked, no changes should be allowed.
I'm fairly certain I can use the ng-disabled directive on each control, but I'd like to set some attribute/class on the entire container, rather than on each individual control.
I am using Bootstrap 3, so if there is a class that would provide this functionality, that would be an acceptable solution as well.
Here is the relevant section of the HTML:
<input type="checkbox" ng-model="status" title="Enable/Disable Schedule" /> <b>Schedule the task to run:</b>
<div class="row"> <!-- need a way to disable this row based on the checkbox -->
<span>Every <input type="number" ng-model="interval" />
<select ng-model="frequency"
ng-options="freq as freq.name for freq in frequencies"></select>
</span>
<div>
On these days:
</div>
<div class="btn-group" data-toggle="buttons-checkbox">
<button type="button"
class="btn"
ng-model="day.value"
ng-repeat="day in days">{{day.name}}</button>
</div>
</div>
I have tried:
<div class="row" ng-disabled="!status">
It didn't work, and based on the docs, it doesn't look like it is even supposed to, as its intended use is for disabling form controls. I also tried without the !, just to validate that it wouldn't work either.
OK, I found a technique that works for my purposes...
<div class="row" ng-class="{disabled: !status}"> <!-- added ng-class here -->
and
.disabled {
z-index: 1000;
background-color: lightgrey;
opacity: 0.6;
pointer-events: none;
}
This prevents clicks on the page and gives a nice visual indication of the section being "disabled".
It does not prevent me from tabbing through the controls, but it works OK for my purposes.

Retain scroll position while model is updated in angular js

i have a list of teams and user can add a team to list of teams. the problem i having is that when i add an item to an list, angular re-renders the list and scroll position is reset to the top.
this is the template
<div ng-controller="scores">
<ul>
<li ng-repeat="team in teams">
{{team.name}}:
<button ng-click="decr(team)">-</button>
{{team.score}}
<button ng-click="incr(team)">+</button>
</li>
</ul>
(+)Add Team
</div>
here is the controller code
function scores($scope){
$scope.teams = [
{name:'red', score:100},
{name:'blue', score:100},
{name:'green', score:100}
];
$scope.decr= function(team){team.score-=1;};
$scope.incr= function(team){team.score+=1;};
$scope.add= function(){$scope.teams.push({name:"...", score:100});};
}
you can see working example here. http://jsbin.com/asedib/5
The problem is that you have href="#", which resets the anchor / scroll position to the top of the page every time you click the link.
I see two easy solutions:
The easiest is to change the anchor to a button. This still makes it clear that this is a clickable element, but without the anchor element:
<button ng-click="add()">(+) Add Team</button>
If you prefer the anchor-style appearance, you can remove the href="#", but then update your CSS to style the non-anchor link to look like a link. Something like this:
<a ng-click="add()" class="clickable">(+) Add Team</a>
And the CSS:
a, a.clickable {
color: blue;
text-decoration: underline;
cursor: pointer;
}
Both of these solutions solve the immediate problem without any extra JavaScript.

Resources