ui-grid custom pagination for child/expandable grid - angularjs

I am using the new UI-grid and need to have a custom pagination logic for both the child and the parent grid.
There is a directive for the custom pagination and this works well when placed along with the main grid . This directive has a few methods for the pagination to set the data for the grids.
But when this directive is placed in the expandablegrid template,I wanted to access the directive methods once the main parent grid is expanded. But I am not able to access those methods
paginator directive :
app.directive('paginator', ["$parse", function ($parse) {
return {
restrict: 'E',
templateUrl: "..pagination.htm",
scope: {
datasource: "="
},
controller: ['$scope', function (scope) {
scope.datasource.computePageNumbers = function () {
//pagination logic
}
}
]
}
}]);
expandableGrid.html
<div class="row">
<div class="col-sm-12">
<div ui-grid="row.entity.subGridOptions" ui-grid-pagination class="grid"></div>
<paginator datasource="row.entity.childPagination" ></paginator>
</div>
</div>
setting values in subGridOptions
$scope.paginationData = {};
$scope.gridOptions.data[i].childPagination=paginationData;
parent grid row expansion code.
Here inside the rowselection I need to call the computePageNumbers and set data in the row.Entity.data which sets data for child grid.
But I am not able to call the computePageNumbers. How to make it work ?
I may not be explaining in detailed but if someone can help it would be help to me or any other alternative.
gridApi.selection.on.rowSelectionChanged($scope, function (row) {
gridApi.expandable.toggleRowExpansion(row.entity)
});
http://plnkr.co/edit/Z6qgbtBzt1qZy4ZVkLbC?p=preview

Related

Two way binding in custom directive with ng-repeat

I basically have a list of items that are stored as an array of objects. Some of these items are "children" of others. This is denoted by a "parentid" setting in each object. This only means that I want to display children as a nested list within the parent.
So, I start by iterating through the array and find one with no parent. When I find it, I call a directive that takes that ID and then again iterates through the main array and finds any item whose parentID is identical to the one in question and displays it. There can be multiple levels of children so that the directive is called recursively.
This works fine and displays all of the children, but I want to be able to select any one of these items and see that ID or object at the top level. This is not working. I pass a variable into each directive with two way binding but no parent is ever updated. I understand the primitive problem and I am passing an object but that is not working. I think that I need to do something with the repeats, but I am not sure what. I do not think transclusion is the issue.
In the demo below, I need to display the updated var3 variable whenever I click on an item.
Initial HTML
<div>{{var3}}</div>
<div>
<my-directive var1="item1"
var2="item2"
var3="item3">
</my-directive>
</div>
Directive
(function ()
{
'use strict';
angular
.module('app.core')
.directive('myDirective', myDirective);
function structureContent($templateRequest, $compile)
{ return {
restrict : 'E',
scope:{
var1:'=',
var2:'#',
var3:'='
},
controller : ["$scope", "$element", "$attrs",
function($scope, $element, $attrs) {
}
],
link : function(scope, element, attrs){
scope.$watch('worksheet',
function(){
$templateRequest("myTemplate.html").then(function(html){
var template = angular.element(html);
element.html(template);
$compile(template)(scope);
});
}, true
);
}
}
};
})();
Directive HTML
<div>
<div ng-click="var3=thisItem.itemid;">(Display item) </div>
// var3 is what I want to be able to pull out at the top level
</div>
<div ng-repeat="thisObj in myArray | orderBy:'order' track by thisObj.itemid"
ng-switch on="thisObj.type_id"
ng-if="thisObj.content.parentid==thisItem.itemid"
class="subSection" >
<div ng-switch-when="1">
<my-directive var1="{{var1}}"
var2="var2"
var3="var3">
</my-directive>
</div>
</div>

Angular - How to use a dynamic templateUrl for a directive?

So, for whatever reason, I am trying to create a slider, where the contents of each slide are different HTML templates. So instead of an image slider, you could say it's a HTML slider.
So in my HTML I just have this code, and the controls for the slider are also inside this HTML template:
<slide-template></slide-template>
And here is my entire slide module:
(function() {
'use strict';
angular
.module('slideCtrl', [])
.directive('slideTemplate', function() {
return {
restrict: 'E',
templateUrl: 'views/slides/slide-1.html',
replace: true,
controller: 'slideController',
controllerAs: 'slides'
}
})
.controller('slideController', function() {
var vm = this;
});
})();
I'm not sure how to move forward with this, I've tried looking around but haven't found anything that I felt I could use. Inside the controller, I would like to have an array of slide template URLs and a corresponding variable to indicate the current slide:
slideUrl = [ 'views/slides/slide-1.html', 'views/slides/slide-2.html'];
slideNum = 0;
Ideally, I would then like my directive to use these variables to determine what variable it will use for templateUrl. So by default, you can see that slideNum is 0, meaning that I want to use slide1.html or slideUrl[0]. So, my templateUrl would be something like slideUrl[slideNum]. Of course, this can't be done as the directive wouldn't be able to access that data, so I'm not sure how to do this.
The end result would be that if you clicked one of the slide navigation icons, you would be updating the slideNum variable, which would instantly change the templateUrl used.
I guess I am essentially wanting a slider which doesn't rely on some images or something like that for content, but instead is a slider of actual HTML content.
Any ideas? If I haven't explained myself well enough, please let me know.
hi I would solve it like this by creating a "main.html" template and in that:
//main.html
<div ng-if="slide == 1">
<ng-include src="'slide1.html'"/>
</div>
<div ng-if="slide == 2">
<ng-include src="'slide2.html'"/>
</div>
<div ng-if="slide == 3">
<ng-include src="'slide3.html'"/>
</div>
//controller
.controller('slideController', function() {
$scope.slide = 1
//logic to switch slides
});
for animations on the slide transitions take a look at this code pen
animations
I would suggest a main directive, where you would place the different slides on one page.
For instance, the main directive:
<div ng-include src="'slider0.html'" ng-if="slider%4==0"></div>
<div ng-include src="'slider1.html'" ng-if="slider%4==1"></div>
<div ng-include src="'slider2.html'" ng-if="slider%4==2"></div>
<div ng-include src="'slider3.html'" ng-if="slider%4==3"></div>
And then in the controller of the directive you set:
$scope.slider = 0;
// Some more logic like:
$scope.slider++;
You could move this to a link function and replace your compiled slide dynamically by adding them to the slideUrl array. This method is flexible enough to allow you to manage the slides in the controller, also you could potentially pass the slide urls to the directive through an scoped attribute.
.directive('slideTemplate', function($http, $compile, $templateCache) {
return {
restrict: 'E',
replace: true,
controller: 'slideController',
controllerAs: 'slides',
link : function(scope, el, attrs) {
// Bind active slide number to controller scope
scope.slides.num = 0;
// Declare slide urls
var slideUrl = [
'views/slides/slide-1.html',
'views/slides/slide-2.html'
];
// Load a slide and replace the directives inner html
// with the next slide.
function loadSlide(template) {
// Get the template, cache it and append to element
$http.get(template, { cache: $templateCache })
.success(function(content) {
el.replaceWith($compile(content)(scope));
}
);
}
// Progress to the next slide, this is bound to the
// controllers scope and can be called from there.
scope.slides.next = function() {
var next = scope.slides.num + 1;
var slide = slideUrl[next] ? next : slide;
scope.slides.num = slide;
loadSlide(slideUrl[slide]);
}
}
}
});

AngularJS - How to show custom directives based on condition

I have to show a custom directive (i.e. task-moveable) based on some condition. I have to only show the task-movable attribute for tasks which is not completed yet. Is there any way we can do this in Angularjs?
HTML Code:
<div class="gantt-body-background" ng-repeat="row in gantt.rows" task-moveable>
....
</div>
Thanks in advance.
You could make a tweak such that your taskMoveable directive can observe a value assigned to it. From there do an $eval on the value of the taskMoveable attribute to get your boolean.
As an example:
app.directive('taskMoveable', function () {
return {
controller: function ($scope, $element, $attrs) {
$scope.taskMoveable = {};
$attrs.$observe('taskMoveable', function (value) {
if (value) {
$scope.taskMoveable.amIMoveable = $scope.$eval(value);
}
});
},
template: '<span ng-bind="taskMoveable.amIMoveable"></span>'
};
});
See my plunk here for a more detailed example:
http://plnkr.co/edit/0nK4K9j3SmNnz8PgRYfR
You could use ng-if for that whole element. Something like this.
<div class="gantt-body-background" ng-repeat="row in gantt.rows" ng-if="thing.stuff" task-moveable>
....
</div>
Then that div would only be in the DOM if thing.stuff was truthy.

Changing src of only hovered ng-include element, where value of src is a $scope variable

I have multiple ng-include elements that have src attribute set to $scope.template_url.
I want to change src of hovered element only to new template but changing it's value will change all of elements. How can i implement it?
Html code:
<section class="parent">
<div data-ng-include data-src="template_url"></div>
</section>
Javascript (in controller):
angular.element(document).on('mouseover', '.parent', function(){
$scope.$apply(function () {
$scope.template_url = "path/to/new/template.html";
});
});
Writing jQuery dom manipulation is dirty and also don't works:
$(this).attr('data-src', "path/to/new/template.html");
I'd suggest making this a directive. Directives have their own scope, so you can still do the "on hover use a different template" idea, but for each individual one that is hovered.
<div>
<div data-some-directive=""></div>
</div>
var myApp = angular.module('myApp',[]);
myApp.directive('someDirective', function() {
return {
controller: function ($scope) {
$scope.model = "Hello"
$scope.mouseover = function () {
$scope.model = "Hovered!";
};
},
scope:{},
restrict: 'AE',
replace: true,
template: '<div><input ng-mouseover="mouseover()" ng-model="model"></div>',
};
});
Heres a fiddle to see it in action.
Tweak the template variable in the directive to use a variable on your model for the include url.
By the way, angular already has a mouseover handler, so i've just linked that into the controller with ng-mouseover in the template.

Ng-controller on same element as ng-repeat - no two-way-data-binding

I can't get two-way-data-binding to work in an Angular js ng-repeat.
I have an ng-controller specified on the same element that has the ng-repeat specified -
I just learnt that by doing this, I can get a hold of each item that is being iterated over by ng-repeat. Here is the HTML:
<div ng-controller="OtherController">
<div id="hoverMe" ng-controller="ItemController" ng-mouseenter="addCaption()"
ng-mouseleave="saveCaption()" ng-repeat="image in images">
<div class="imgMarker" style="{{image.css}}">
<div ng-show="image.captionExists" class="carousel-caption">
<p class="lead" contenteditable="true">{{image.caption}}</p>
</div>
</div>
</div>
</div>
And here is the ItemController:
function ItemController($scope){
$scope.addCaption = function(){
if($scope.image.captionExists === false){
$scope.image.captionExists = true;
}
}
$scope.saveCaption = function(){
console.log($scope.image.caption);
}
}
And the OtherController:
function OtherController($scope){
$scope.images = ..
}
When I hover the mouse over the #hoverMe-div - the caption-div is added correctly. But when I input some text in the paragraph and then move the mouse away from the #hoveMe-div, the $scope.image-variables caption value is not updated in the saveCaption-method. I understand I'm missing something. But what is it?
You don't need a ng-controller specified on the same element that has the ng-repeat to be able to get each item.
You can get the item like this:
<div ng-repeat="image in images" ng-mouseenter="addCaption(image)" ng-mouseleave="saveCaption(image)" class="image">
And in your controller code:
$scope.addCaption = function (image) {
if(!image.captionExists){
image.captionExists = true;
}
};
To get contenteditable to work you need to use ng-model and a directive that updates the model correctly.
Here is a simple example based on the documentation:
app.directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, controller) {
element.on('blur', function() {
scope.$apply(function() {
controller.$setViewValue(element.html());
});
});
controller.$render = function(value) {
element.html(value);
};
}
};
});
Note that the directive probably needs more logic to be able to handle for example line breaks.
Here is a working Plunker: http://plnkr.co/edit/0L3NKS?p=preview
I assume you are editing the content in p contenteditable and are expecting that the model image.caption is update. To make it work you need to setup 2 way binding.
2 way binding is available for element that support ng-model or else data needs to be synced manually. Check the ngModelController documentation and the sample available there. It should serve your purpose.

Resources