ng-click inside cell template does not trigger function in controller - angularjs

I have created a plunker here: http://plnkr.co/edit/zGqouwzxguef13lx48iP?p=preview
When I click in a cell of the ui-grid in the day view then nothing happens. What I expected is that the test function is executed and an alert is shown with text 'test' but that is not the case.
What is going on wrong here?
Thats the html cell template of the ui-grid 3.0 latest release:
HTML
<div ng-click="test()" ng-switch="row.entity[row.grid.columns.indexOf(col)].isPeriod">
<div ng-switch-when="true">
<tabset>
<tab>
<tab-heading>
<i class="glyphicon glyphicon-book"></i>
</tab-heading>period id:
{{ row.entity[row.grid.columns.indexOf(col)].id}}
</tab>
<tab select="alertMe()">
<tab-heading>
<i class="glyphicon glyphicon-bell"></i>
</tab-heading>
{{row.entity[row.grid.columns.indexOf(col)].content}}
</tab>
</tabset> <!-- PeriodTemplate -->
</div>
<div ng-switch-when="false">
<div>Hello empty template</div>
</div> <!-- EmptyPeriodTemplate -->
</div>
CONTROLLER:
'use strict';
angular.module('projectplanner').controller('DateplannerDayController', function ($scope, $state) {
var columnHeaderDates = ['col1','col2','col3','col4','col5','col6','col7']
$scope.columns = createColumnHeaders(columnHeaderDates);
var data = [{isPeriod: true, id: 10, rowNumber: 1},{isPeriod: false, id: 11, rowNumber: 2}]
$scope.test = function()
{
alert('test');
};
$scope.gridOptions = {
rowHeight: 200,
data: data,
enableSorting: false,
enableColumnMenu: false,
columnDefs: $scope.columns,
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
$scope.gridApi.core.addRowHeaderColumn(
{ name: 'rowHeaderCol',
displayName: '',
width: 100,
cellTemplate: '<div>row header template</div>'
});
}
};
function createColumnHeaders(columnHeaders) {
var columnDefinitions = [];
for (var i = 0; i < columnHeaders.length; i++) {
var column = {
name: columnHeaders[i],
cellTemplate: 'lessonplanner.day.celltemplate.html',
field: i + 'x'
}
columnDefinitions.push(column);
}
return columnDefinitions;
}
});

This page kept popping up in my searches and I managed to miss the solution in the comments. To summarize, you likely need to use externalScopes. See Angular ui-grid events in cell header not firing and http://ui-grid.info/docs/#/tutorial/305_appScope

If you are using Controller-As syntax then try:
ng-click= "grid.appScope.<controllerAliasName>.myFunction(row)"

It is because the ui-grid has its own controller and it doesn't know about the outside controller.
To facilitate, do the following..
1. First assign the controller to the ui-grid.
var vm = this;
this.$scope.usersGridOptions = {
appScopeProvider: vm,
....
}
Now, once you assign the controller to the grid, you can invoke the function like this..
"<a type=\"button\" href=\"\" ng-click=\"function(row.entity)\"> {{ row.entity.text}} </a>"

In ui-grid, cell-template, because of cell has its own scope,
1) do not use onclick='', instead should use ng-click=''
2) ng-click='your_function()' will not work, should use, grid.appScope.your_function()
3) when pass parameter in function(), do not use function({{xxx}}), see sample below
cellTemplate: '<div class="ui-grid-cell-contents" title="TOOLTIP">{{grid.appScope.editLink_tree_id(grid, row)}}</div>'

Related

angularjs $compile html template in forEach not update variables

I want to dynamically generate html. I have generateHtml function contains loop for items, currently it is not displaying proper variables added in template. It is always display the last items data on all the iteration on compiled html.
Following is the controller & template code
This is my controller code
angular.module('app').controller('PageController', ['$scope', '$sce', '$compile','$templateRequest',
function ($scope, $sce, $compile,$templateRequest) {
$scope.itemsHtml = '';
// Array contains dynamic data
vm.items = [{
id: 1,
name: 'abc',
}, {
id: 2,
name: 'pqr',
}, {
id: 3,
name: 'stu',
}, {
id: 4,
name: 'xyz',
}];
vm.currentItem = [];
let templateUrl = $sce.getTrustedResourceUrl('/views/item.html');
$templateRequest(templateUrl).then(function(template) {
vm.itemTemplate = template;
}, function() {
});
vm.generateHtml = function() {
items.forEach(function (item, key) {
vm.currentItem = item;
let compiledTemplate = $compile(vm.itemTemplate)($scope).html();
/* Append compiled dynamic html */
$scope.itemsHtml += compiledTemplate;
});
}
function init() {
vm.generateHtml();
}
init();
}
]);
This is template view
<script type="text/ng-template" id="item.html">
<div className="item-wrapper">
<div className="item-inner">
{{ pageCtrl.currentItem.name }}
</div>
<div className="action-inner">
<div className="btn-action"
role="button"
ng-click="pageCtrl.edit(
pageCtrl.currentItem.id
)">
<i className="fa fa-plus"></i>
</div>
</div>
</div>
</script>
I got the solution for this issue.
Actually when we use compile after that we have to interpolate the compiled template
compiledTemplate = $interpolate(compiledTemplate)($scope);
let compiledTemplate = $compile(vm.itemTemplate)($scope).html();
/* Here interpolated compiled template */
compiledTemplate = $interpolate(compiledTemplate)($scope);
/* Append compiled dynamic html */
$scope.itemsHtml += compiledTemplate;

Angular ng-if with Kendo UI autocomplete issue

I've just created an autocomplete Kendo input field inside a div which has to be controlled by a ng-if, because it has to be shown only to a particular category of users.
But I finally get rendered on my browser only a normal input field with no autocomplete properties.
If I remove the ng-if directive or even if I transform it to ng-show it works properly.
This is my HTML:
<div ng-if="utenteProfilo=='PB'">
<label for="PB" class="col-sm-2 control-label">PB</label>
<div class="col-sm-4">
<input ng-model="codPB" class="cento" id="codPB" />
<input type="hidden" id="cognomePb" name="cognomePb" />
<input type="hidden" id="nomePb" name="nomePb" />
</div>
</div>
This is my JS:
$("#codPB").kendoAutoComplete({
placeholder: "Scegliere un PB...",
dataTextField: 'PBanker',
filter: "contains",
autoBind: false,
minLength: 3,
headerTemplate: '<div class="dropdown-header k-widget k-header">' +
'<span>Cognome</span>' +
'<span>Nome</span>' +
'</div>',
template: '<span class="k-state-default" ></span>' +
'<span class="k-state-default"><h6 data-recordCognomePB="#= cognome #" data-recordNomePB="#= nome #">#: data.cognome # #: data.nome #</h6></span>',
select: function(e) {
var cognomePb = e.item.find('h6').attr('data-recordCognomePB');
var nomePb = e.item.find('h6').attr('data-recordNomePB');
$('#cognomePb').val(cognomePb);
$('#nomePb').val(nomePb);
},
filtering: function(e) {
$('#cognomePb').val('');
$('#nomePb').val('');
},
dataSource: {
schema: {
parse: function(response) {
var length = response.length;
var dataItem;
var idx = 0;
for (; idx < length; idx++) {
dataItem = response[idx];
dataItem.PBanker = dataItem.cognome + " " + dataItem.nome;
}
return response;
}
},
serverFiltering: true,
transport: {
read: {
url: "http://myFile.json",
data: function(){
return {pb: $('#codPB').val()}
}
}
},
},
});
Do you know any issues about this behavior? Am I acting something wrong?
Try to avoid querying the DOM (with $("#codPB").kendoAutoComplete()) when using angular. You are mixing two different approaches.
In this case, Kendo provides directives to work with angular, see this demo:
HTML
<input kendo-auto-complete ng-model="country"
k-data-source="countryNames" style="width: 100%;" />
JS
angular.module("KendoDemos", [ "kendo.directives" ])
.controller("MyCtrl", function($scope){
$scope.countryNames = [
"Albania",
"Andorra",
//[...]
"Ukraine",
"United Kingdom",
"Vatican City"
];
});
The other solution (less elegant) is to use ng-show instead of ng-if.

How to copy selction into a new ui-grid

I am using Angular ui-grid (from ui-grid.info).
I have one ui-grid showing JSON Data delivered by a webapi-controller what works perfectly.
I added a second ui-grid with the same columsDef but no data.
I want to copy the (multi-)selected rows from grid1 to grid 2 using a button.
How would I access the selection to add it into the data of the second grid?
app.js
var app = angular.module('app', ['ui.grid', 'ui.grid.grouping','ui.grid.selection']);
app.controller('MainCtrl', ['$scope', '$http', '$log', 'i18nService', '$interval', 'uiGridGroupingConstants', function ($scope, $http, $log,i18NService, $interval, uiGridGroupingConstants) {
$scope.langs = i18NService.getAllLangs();
$scope.lang = 'de';
i18NService.setCurrentLang('de');
$scope.gridOptions = {
rowSelection:true,
enableFiltering: true,
enableRowSelection: true,
enableFullRowSelection :true,
enableSelectAll: true,
selectionRowHeaderWidth: 35,
rowHeight: 75,
showGridFooter:true,
treeRowHeaderAlwaysVisible: true,
columnDefs: [
{ name: 'Trigraph',field:'ZeigeTrigraphen',width:'10%'},
{ name: 'Titel', field: 'Titel', cellTemplate: '<td style="word-wrap:break-word;padding:5px;">{{ COL_FIELD }}</td>' },
{ name: 'Ziel', field: 'Ziel', cellTemplate: '<td style="word-wrap:break-word;padding:5px;">{{ COL_FIELD }}</td>' },
],
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
}
};
i18NService.setCurrentLang('de');
$http.get('/api/Alarmkalender/HoleAlle').then(function (resp) {
$scope.gridOptions.data = resp.data;
$log.info(resp);
});
html
<div class="container" ng-app="app">
#*<link rel="styleSheet" href="../../Scripts/ui-grid/ui-grid.min.css" />*#
<style>
.grid {
width: auto;
height: 350px;
}
</style>
<h2>Alarmmassnahmen</h2>
<div ng-controller="MainCtrl">
<div id="grid1" ui-grid="gridOptions" ui-grid-grouping class="grid"></div>
<button name="SpeichernButton" class="btn btn-success" id="btnSpeichern" type="submit" value="SpeichernButton"><i class="glyphicon glyphicon-save"></i> In Alarmkalender kopieren</button>
<div id="grid2" ui-grid="gridOptions2" class="grid"></div>
</div>
There are several ways to achieve your goal. I made a Plunker to demonstrate a possible solution.
You could create an ng-click on the row-template and gather all row selections. You either instantly load them into the new grid (as shown in Plunker) or load them all on external button-click.
There are basically three steps
First modify the row-Template
$templateCache.put('ui-grid/uiGridViewport',
...
"<div ng-repeat=\"(rowRenderIndex, row) in rowContainer.renderedRows track by $index\"" +
"ng-click=\"grid.appScope.addRowtoSelection(row)\"" +
...
);
Then you bind that addRowtoSelection() to your first grid and push selected rows into an array.
all.relectedRows = [];
all.gridOptions = {
...
appScopeProvider : {
addRowtoSelection : function(row) {
all.relectedRows.push(row.entity);
},
},
};
Finally you bind that array as new data to your second grid.
all.gridOptionsTwo = {
data: 'all.relectedRows',
...
};
e: If you want to use a button instead of instant addition of rows, you could use selectedRows as temporary array and reference selectedRowsData in your second grid. See updated Plunker.
HTML
<button ng-click="all.addRowsToSecondGrid();">Add Rows</button>
JavaScript
all.relectedRowsData = [];
all.addRowsToSecondGrid = addRowsToSecondGrid;
function addRowsToSecondGrid() {
all.relectedRowsData = [];
all.relectedRowsData = all.relectedRowsData.concat(all.relectedRows);
}
all.gridOptionsTwo = {
data: 'all.relectedRowsData',
...
Hopefully that helps.

Angular ng-repeat issue

I've this controller:
app.controller('HomeController', function($scope) {
$scope.buttonList = [
{
href: "http://ciao.html",
cssClass: "",
iconBeforeCssClass: "",
labelCssClass: "",
labelText: "ciao",
iconAfterCssClass: "",
},
{
href: "ciao2.html",
cssClass: "",
iconBeforeCssClass: "",
labelCssClass: "",
labelText: "ciao2",
iconAfterCssClass: "",
}
];
});
This directive:
app.directive('widgetButtonList', function() {
var directive = {};
directive.restrict = 'E';
directive.replace = false;
directive.templateUrl = 'modules/directives/widget-button-list.html';
directive.scope = {
additionalCssClass: "#",
buttons : "#",
};
return directive; });
The template is the follow:
<div class="ap-block ap-button-list-block {{additionalCssClass}}">
<ul>
<li ng-repeat="btn in buttons track by $index">
<a href="{{btn.href}}" class="{{btn.cssClass}}">
<i class="ap-button-list-before-icon {{btn.iconBeforeCssClass}}" ></i>
<span class="ap-button-list-label {{btn.labelCssClass}}">{{btn.labelText}}</span>
<i class="ap-button-list-after-icon {{btn.iconAfterCssClass}}" ></i>
</a>
</li>
</ul>
And the view is like this:
<div ng-controller="HomeController">
<widget-button-list buttons="{{buttonList}}"></widget-button-list>
But otherwise to render two times the template button as i expected, it print 250 time the widget's template without binding nothing. Can someone help me??
You'll want to pass the buttonsList using a different isolate scope attribute instead of using text-binding. The # symbol on the directive definition object indicates you'll be passing in a string, where you're actually passing in an array of objects. Try this:
directive.scope = {
additionalCssClass: "#",
buttons : "=" //instead of #
};
<widget-button-list buttons="buttonList"></widget-button-list>
Plunker Demonstration
And just for the sake of completeness, you could pass in the buttonsList as a string, but you'll have to be aware that in the directive you'll be recieving a JSON string. Then you'll need to parse it inside the directive:
directive.scope = {
additionalCssClass: "#",
buttons: "#"
};
directive.controller = function($scope) {
$scope.btns = JSON.parse($scope.buttons);
}
I don't suggest this second method, but here's the Plunker Demonstration of that as well.

How to make checkbox cell edit template in ng-grid?

I am new to ng-grid. I am learning ng-grid with edit template options. i have created grid with edit checkbox options.But i don't know How to get value in that grid after edit the checkbox? Thank you.
Here JSfiddle.
var myapp = angular.module('myapp', ["ui", "ngGrid"]);
myapp.controller('myctrl', function($scope, $http) {
$scope.testInfo= "TestInfo";
$scope.data = {
persons: [],
selected:[],
load: function () {
$http.get("/echo/json/").success(function(data) {
$scope.data.persons = [
{id:1, name:"Max", number:51323.512,value:'on'},
{id:2, name:"Adam", number:7245.2,value:'on'},
{id:3, name:"Betty", number:828,value:'off'},
{id:4, name:"Sara", number:23452.45182,value:'on'}
];
$scope.data.selected[0] = $scope.data.persons[0];
});
}
};
var cellTemplate = "<div ng-class=\"'ngCellText colt' + $index\">"
+ " <span ng-cell-text>{{COL_FIELD}}</span>"
+ "</div>";
var cellEditTemplate = '<input type="checkbox" ng-checked="row.entity.value==\'on\'" ng-input="COL_FIELD" /></div>';
$scope.grid = {
options: {
data: "data.persons",
selectedItems: $scope.data.selected,
multiSelect: false,
columnDefs: [
{field:"id", displayName:"ID"},
{field:"name", displayName:"Name"},
{field:"number", displayName:"Nummer", cellFilter:"number:2"},
{field: "value",displayName:"Value",enableCellEdit : true,cellTemplate : cellTemplate,
editableCellTemplate : cellEditTemplate}
]
}
};
});
<div ng-app="myapp">
<div ng-controller="myctrl">
<a class="btn" ng-click="data.load()">Get data!</a>
<div ng-grid="grid.options" class="grid"></div>
<ul ng-repeat="item in data.selected">
<li>{{item}}</li>
</ul>
</div>
</div>
You've probably already figured this out by now, but one possible options is to use ng-grids build in checkbox selector. It's not shown in the examples on their main page, but listed as an option in the API.
showSelectionCheckbox: true

Resources