I am trying to set elements to the same height using jQuery.matchHeight. I call the function from an Angular directive
angular.module('myApp')
.directive('matchHeight', ['$timeout', function ($timeout) {
var linkFunction = function(scope, element) {
$timeout(function() {
angular.element(element).matchHeight();
});
};
return {
restrict: 'A',
link: linkFunction
};
}]);
The matchHeight plugin and jQuery are included in index.html
<html>
<head>
all head stuff
</head>
<body>
<div class="row usps">
<div class="col-sm-4 usp-block" ng-repeat="block in content.marketing" match-height>
<a href="{{block.link_url}}" class="thumbnail">
// Rest of html
</a>
</div>
</div>
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/matchHeight/dist/jquery.matchHeight.js"></script>
<script src="scripts/app.js"></script>
<script src="scripts/directives/matchheight.js"></script>
</body>
</html>
The problem is that the height is not set although the directive is being applied to the element.
The jQuery.matchHeight plugin will set all the items in an array to the height of the tallest element in that array.
the match-height directive is applied to a single element. Because there is no array, the height is not set on the element.
Moving the directive to the parent element in the DOM and adding the class equal to the child element(s) gives the array needed to set the height.
<div class="row usps" match-height>
<div class="col-sm-4 usp-block equal" ng-repeat="block in content.marketing">
<a href="{{block.link_url}}" class="thumbnail">
// Rest of html
</a>
</div>
</div>
In the service I apply the matchHeight function to all elements with the class equal
angular.module('myApp')
.directive('matchHeight', ['$timeout', function ($timeout) {
var linkFunction = function(scope, element) {
$timeout(function() {
angular.element(element).find('.equal').matchHeight();
});
};
return {
restrict: 'A',
link: linkFunction
};
}]);
Check this out, guys.
https://github.com/christopher-weir/AngularJs-MatchHeight
this custom directive is working fine. Also, codebase is pretty simple you can tweaks as your project need.
Related
I like to add custom directory in element which is run-time added from script.
eg: <input type="number" my-focus = "focusField" > in this i am adding 'my-focus' directive from html.
Can I add this directive from JavaScript because my element is dynamically added and I want to add focus on that element.
You can use $compile
Compiles an HTML string or DOM into a template and produces a template function, which can then be used to link scope and the template together.
Here is an example
$scope.html = $compile('<a ng-click="click()" href="#">Click me</a>')($scope);
(function(angular) {
'use strict';
angular.module('myApp', [])
.controller('Controller', ['$scope','$compile',
function($scope, $compile) {
$scope.html = $compile('<a ng-click="click()" href="#">Click me</a>')($scope);
angular.element(document.querySelector('#x')).append($scope.html);
$scope.click = function() {
console.log('Yahoooooooooooo')
}
}
]);
})(window.angular);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="Controller">
<div id="x">
</div>
</div>
</div>
Here is my full test code:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.16/angular.min.js"></script>
<script>
angular.module('app', []).controller('MainController',['$scope', function($scope){
$scope.model = {
showList: false,
list:[1,2,3,4]
}
}]).directive('withTransclude', function(){
return {
restrict: 'E',
replace: true,
transclude: true,
template:'<div><span>transclude container</span><ng-transclude></ng-transclude></div>',
link:function($scope, $element, attr, ctrl, transclude){
// i dont want the ng-transclude tag so i replaced it
// if comment this expression problem disappear but the ng-transclude tag remains
$element.find('ng-transclude').replaceWith(transclude());
}
}
})
</script>
</head>
<body ng-app='app' ng-controller="MainController">
<button ng-click='model.showList = !model.showList'>toggle show</button>
<div ng-if="model.showList">
<span>shown</span>
<with-transclude>
<div>hello</div>
<ul>
<li ng-repeat="number in model.list">{{number}}</li>
</ul>
</with-transclude>
</div>
</body>
</html>
Problem:
When using ng-transclude, I don't want the ng-transclude tag remains in my page, so i replaced it with the transcluded content,but when toggle ng-if by clicking button, more and more ng-repeat element got rendered, if I don't replace,it's ok.
Question:
Why this problem occurred? and is there any other way to remove the ng-transclude tag, which doesn't give this problem.
Change:
$element.find('ng-transclude').replaceWith(transclude());
To:
var transcludeEl = $element.find('ng-transclude')
$element.append(transcludeEl.contents())
transcludeEl.remove();
https://plnkr.co/edit/7zw27ldkGp0zeey5z9QI?p=preview
try with ng-show instead of ng-if.....i didn't see the repetition when using ng-show
<div ng-show="model.showList">
CHECK it
I am trying to implement jquery-ui's sortable on the elements inside the ng-repeat.
Problem : i cannot actually do the sortable action on the elements inside the ng-repeat.
I've checked for answers. My code seems similar to most answers which apparently work, but my code doesn't work
Below is the html snippet:
<div class="container-fluid rt-widget-list-dim-adj">
<div my-dir>
<div ng-repeat="widget in model.widgets" ng-switch="widget.widgetType">
<div ng-switch-when="HEADER">
<ng-include src="'views/widget/widget-header.view.client.html'">
</div>
<div ng-switch-when="IMAGE">
<ng-include src="'views/widget/widget-image.view.client.html'">
</div>
<div ng-switch-when="YOUTUBE">
<ng-include src="'views/widget/widget-youtube.view.client.html'">
</div>
</div>
</div>
</div>
my app.js:
(function(){
angular.module("myApp", ['ngRoute', 'myDir']);
})();
below is my custom directive:
(function () {
angular
.module("myApp", [])
.directive("myDir", makeSortable);
function makeSortable() {
var directive = {
restrict : 'ACE',
link : linker
};
function linker(scope, element, attrb) {
element.sortable();
}
return directive;
}
})();
element in linker function args is not jQuery, it is a jqLite wrapper.
If you want to apply jQuery, try this:
$j(element[0]).sortable();
When I click my-dir, collapsed elements won't expand.
I have set size in css for .btn class to ensure actually click event.
// index.html
<body ng-controller="ctrl">
<p>{{hello}}</p>
<div class="btn" my-dir></div>
</body>
// app.js
var app = angular.module('app', ['ui.bootstrap']);
app.controller('ctrl', function($scope){
$scope.hello = 'hello';
});
app.directive('myDir', function() {
return {
restrict: 'A',
replace: false,
templateUrl: './tmpl.html',
link: function (scope, element, attrs) {
scope.isCollapsed = true;
element.bind('click', function (e) {
scope.isCollapsed = !scope.isCollapsed;
})
}
};
});
// tmpl.html
<div class="dir-box">
<div uib-collapse="isCollapsed">
<p>Hello World!</p>
<p>Nice to meet You!</p>
<p>: )</p>
</div>
</div>
Why uibCollapse does not work in this situation ?
Any ideas ?
plunker here
There are 2 things that you need to fix:
1.Change click binding to ng-click. By default angular does not run its $digest cycle on jquery events. You can fix that by adding $scope.$apply() or $timeout in your code, but I recommend using ng-click as a more proper way.
<div class="btn" my-dir ng-click="isCollapsed = !isCollapsed"></div>
By your original code I should add it inside your directive template, but your dir-box position does not overlap with the blue area...
2.Use overflow:hidden on uib-collapse element.
<div uib-collapse="isCollapsed" style="overflow: hidden;">
The contents were still showing when the parent height is 0
plunker
I have some content on my site that doesn't format well because different browsers/screens render the font-size a little differently. To counteract this, I'm attempting to use Angular to get the height of some <p> tags, and if they're taller than my layout allows, lower their font size.
The <p> tags I'm trying to manipulate are contained in a directive which generates multiple content boxes based on some JSON.
I have created this directive:
spaModule.directive ("resizeParagraph", function() {
return function (scope, element, attrs) {
while (element.height() > 400) {
element.css("font-size", (parseInt(element.css("font-size")) -1 + "px"));
}
}
});
This is the directive which creates those boxes (this works):
<div ng-repeat="data in homeCtrl.homeData" class="content-box">
<img class="content-image" ng-src="images/home/{{ data.imageSrc }}"/>
<div class="sub-content">
<h1>
{{ data.heading }}
</h1>
<p resize-paragraph class="large-text">
{{ data.body }}
</p>
<a ng-href="#/{{ data.linkUrl }}" class="box-link">
{{ data.linkValue }}
</a>
</div>
</div>
I'm at home creating custom directives with a source URL, but this is my first go at creating a logical attribute-based directive.
What have I done wrong?
Try adding jQuery, before loading angular.js. In this post, it is written that Angular is using its own library jqLite to substitute for jQuery when the jQuery library is not included. jqLite does not include a height() function. To be able to use height(), you have to include the full jQuery library.
Just add <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.js"></script> before the line where you include angular.js.
I tested it with the following code:
<style type="text/css">
.large-text {
font-size: 600px;
}
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.js"></script>
<script src="angular.js"></script>
<script type="text/javascript">
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.homeCtrl = {};
$scope.homeCtrl.homeData = [
{
heading: 'Heading',
body: 'Body',
linkValue: 'LinkValue'
}
];
});
app.directive("resizeParagraph", function() {
return function (scope, element, attrs) {
while (element.height() > 100) {
element.css("font-size", (parseInt(element.css("font-size")) -1 + "px"));
}
}
});
</script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="data in homeCtrl.homeData" class="content-box">
<img class="content-image" ng-src="images/home/{{ data.imageSrc }}"/>
<div class="sub-content">
<h1>
{{ data.heading }}
</h1>
<p resize-paragraph class="large-text">
{{ data.body }}
</p>
<a ng-href="#/{{ data.linkUrl }}" class="box-link">
{{ data.linkValue }}
</a>
</div>
</div>
</div>
EDIT
After some testing, I found the reason why it is not working as expected. The function inside the directive is called, before the expression {{data.body}} is executed in the template. It means that at the moment the directive is called, the text inside the paragraph is literally {{data.body}}. What you want is to postpone the execution of the directive after the expression has been executed. You can do it as follows:
app.directive("resizeParagraph", function() {
return function (scope, element, attrs) {
scope.$watch(name, function () {
while (element.height() > 50) {
element.css("font-size", (parseInt(element.css("font-size")) -1 + "px"));
}
})
}
});
I can also confirm that element.height() and element.context.offsetHeight return the same value. The height of the element in px. So, it doesn't matter which of the two you'll use.
I hope this helps.