I'm trying to turn an existing jquery plugin into a directive to use in my angular app.
My html:
<div ng-controller="BoxController">
<ul class="bxslider" bx-slider="{mode: 'horizontal', pager: false, controls: true, minSlides: 1, maxSlides:4, slideWidth: 350, slideMargin:10, infiniteLoop: false, hideControlOnEnd: true}">
<li ng-repeat="obj in items track by $index">
<div class="item"><img ng-src="{{obj + $index}}" /></div>
</li>
</ul>
</div>
So my directive is bx-slider or bxSlider
app.directive('bxSlider', function()
{
return {
restrict: 'A',
link: function(scope, element, attrs)
{
angular.element(element).bxSlider(scope.$eval(attrs.bxSlider));
}
}
});
What happens is I get a list of images in a bulleted list. The CSS is certainly getting applied however the actions of it being a carousel isn't working. It is supposed to be something like this:
http://bxslider.com/examples/carousel-dynamic-number-slides
However I get
http://dopserv1.dop.com/bxslider/
with no errors in the console or anything. If I do a console.log on attrs.bxSlider I see all the params I defined in the HTML above. What am I doing wrong here? I am including jQuery 1.10.2 above the angular include.
Here's working example: http://plnkr.co/edit/KCwzmG?p=preview
With the part of the solution coming from here.
HTML
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link href="style.css" rel="stylesheet" />
<link href="http://bxslider.com/lib/jquery.bxslider.css" rel="stylesheet" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://bxslider.com/lib/jquery.bxslider.js"></script>
<script src="http://code.angularjs.org/1.2.3/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div data-ng-controller="BoxController">
<ul class="bxslider" data-bx-slider="mode: 'horizontal', pager: false, controls: true, minSlides: 1, maxSlides:4, slideWidth: 350, slideMargin:10, infiniteLoop: false, hideControlOnEnd: true">
<li data-ng-repeat="obj in items track by $index" data-notify-when-repeat-finished>
<div class="item">
<img data-ng-src="http://lorempixel.com/400/200/sports/{{$index + 1}}/" />
</div>
</li>
</ul>
</div>
</body>
</html>
JS
var app = angular.module('plunker', []);
app.controller('BoxController', ['$scope', function ($scope) {
$scope.items = [1, 2, 3, 4, 5];
}]);
app.directive('bxSlider', [function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$on('repeatFinished', function () {
console.log("ngRepeat has finished");
element.bxSlider(scope.$eval('{' + attrs.bxSlider + '}'));
});
}
}
}])
.directive('notifyWhenRepeatFinished', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('repeatFinished');
});
}
}
}
}]);
Related
Angular directive is not working for the following case. In the my following angular application I have two kinds of item I wish to display which are stored in controller.
To display them I have created the directives for both cases, and iterating over list with ng-repeat, but the items are not being rendered.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<style media="screen">
.selected {
background: #cdcdcd;
}
</style>
</head>
<body ng-app="myApp">
<div ng-controller="ListController as listctrl">
<div class="" ng-repeat="item in listctrl.items">
<itemtype1 ng-if="item.type_ === 'type1'" val="item.val"></itemtype1>
<itemtype2 ng-if="item.type_ === 'type2'" val="item.val"></itemtype2>
</div>
</div>
<script type="text/javascript">
angular
.module('myApp',[])
.controller('ListController', function($scope) {
var listctrl = this;
listctrl.items = [];
listctrl.items.push({'val':'A', 'type_': 'type1'});
listctrl.items.push({'val':'B', 'type_': 'type2'});
listctrl.items.push({'val':'C', 'type_': 'type1'});
listctrl.items.push({'val':'D', 'type_': 'type2'});
})
.directive('itemtype1', function() {
return {
template: '<strong>{{$scope.val}}</strong>',
restrict: 'E',
scope: {
val: '='
},
link: function postLink(scope, element, attrs) {
}
};
})
.directive('itemtype2', function() {
return {
template: '<i>{{$scope.val}}</i>',
restrict: 'E',
scope: {
val: '='
},
link: function postLink(scope, element, attrs) {
}
};
});
</script>
</body>
</html>
My first guess, just glancing through it, is that you should change the following:
template: '<strong>{{$scope.val}}</strong>'
to this:
template: '<strong>{{val}}</strong>'
I'm new to angularJS. When I click a button it will show a dialog, the dialog's html code is:
<img id="imgId" ng-src="{{imgSrc}}">
In controller, when I try to access imgId using JavaScript it showing null. Same with the JQuery.
console.log(document.getElementById('imgId')); // null
Here is my code:
angular.module('BlankApp', ['ngMaterial']).
controller('mainController', function($scope, $mdDialog) {
$scope.showCustomDialog = function(ev) {
$mdDialog.show({
controller: DialogController,
template: '{{hello}}<img id="imgId" ng-src="{{imgSrc}}">',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: true
});
function DialogController($scope, $timeout) {
$scope.hello = "Hello World";
$scope.imgSrc = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcScku8D7qo2hWD-eqb_WKTVjMjjiJFLo7uDQQ4RZWRNw9TJ-j7nYg";
$timeout(function() {
console.log(document.getElementById('imgId'));
console.log(angular.element(document.getElementById('imgId')));
});
}
}
});
<html lang="en">
<head>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">
</head>
<body ng-app="BlankApp" ng-controller="mainController" ng-cloak>
<md-button ng-click="showCustomDialog($event)" class="md-primary">Show Dialog</md-button>
<!-- Angular Material requires Angular.js Libraries -->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js"></script>
<!-- Angular Material Library -->
<script src="http://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.js"></script>
</body>
</html>
(plunker)
You need to give the dialog a chance to render, before you can get a reference to it.
Wrap the getElementById calls in a $timeout:
$timeout(function(){
console.log(document.getElementById('imgId'));
console.log(angular.element(document.getElementById('imgId')));
});
Keep in mind that you need to include the $timeout in your controller:
function DialogController($scope, $timeout) {
Here's a working example using your plunker's code:
angular.module('BlankApp', ['ngMaterial']).
controller('mainController', function($scope, $mdDialog) {
$scope.showCustomDialog = function(ev) {
$mdDialog.show({
controller: DialogController,
template: '{{hello}}<img id="imgId" ng-src="{{imgSrc}}">',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: true
});
function DialogController($scope, $timeout) {
$scope.hello = "Hello World";
$scope.imgSrc = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcScku8D7qo2hWD-eqb_WKTVjMjjiJFLo7uDQQ4RZWRNw9TJ-j7nYg";
$timeout(function() {
console.log(document.getElementById('imgId'));
console.log(angular.element(document.getElementById('imgId')));
});
}
}
});
<html lang="en">
<head>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">
</head>
<body ng-app="BlankApp" ng-controller="mainController" ng-cloak>
<md-button ng-click="showCustomDialog($event)" class="md-primary">Show Dialog</md-button>
<!-- Angular Material requires Angular.js Libraries -->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js"></script>
<!-- Angular Material Library -->
<script src="http://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.js"></script>
</body>
</html>
I'm trying to modify the input element using a custom AngularJS directive. Basically I want to replace any <input type="country"> fields with a country drop-down.
But the directive doesn't seem to work with input fields. If I change it to any other tag, it works?
Here is the code:
angular.module('plunker', [])
.controller('MainCtrl', function ($scope) {
$scope.name = 'World';
});
angular.module('plunker')
.directive('input', function() {
return {
restrict: 'E',
scope: {ngModel: '=?'},
link: function(scope, elem, attr) {
if(attr.type === 'country') {
elem.html('html code for select');
alert(elem);
}
}
};
});
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
Name: <input type="country" ng-model="name"/> <br/>
</body>
</html>
Can someone please explain and suggest a workaround?
P.S. I've also tried doing this in the directive, but it doesn't work either!
replace: true,
template:'<div>hello</div>'
P.S. I know I can use a ng-country or some other custom tag but I want to change input tag only because I want learn why this is happening or possibly find out what I'm doing wrong?
Latest Update:
Your code is just setting the html on the element, instead of replacing it. You would want to use replaceWith instead like this:
var app = angular.module("TestApp",[]);
app.controller("TestController", function($scope){
$scope.message = "Input Directive Test"
});
app.directive("input", function() {
return {
restrict: "E",
link: function(scope, elem, attr) {
if(attr.type === "country") {
var select = angular.element("<select><option>USA</option></select>");
elem.replaceWith(select);
}
}
}
});
And here's the JSBin: https://jsbin.com/juxici/4/edit?html,js,output
Initial Version of my answer:
Here's an example that works without any issues when 'replace' and 'template' are used. I'm not checking for type and such, but you could do that in the linker code.
JSBin: https://jsbin.com/juxici/2/edit?html,js,output
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
</head>
<body ng-app="TestApp">
<div ng-controller="TestController">
<h2>{{message}}</h2>
<input type="country" ng-model="name"/>
</div>
</body>
</html>
Javascript:
var app = angular.module("TestApp",[]);
app.controller("TestController", function($scope){
$scope.message = "Input Directive Test"
});
app.directive("input", function() {
return {
restrict: "E",
replace: true,
template:"<select><option>USA</option></select>"
}
});
can you please tell me how to make dirctive in angular js .I need to use owl carousel plugin in js as I did in jqm fiddle http://jsfiddle.net/ezanker/o9foej5L/1/
.I need to make same thing in angular using directive can you please tell me how I will implement this using directive
http://plnkr.co/edit/4ySYwsqrBKUJUj6MwoRY?p=catalogue
<!DOCTYPE html>
<html>
<head>
<link data-require="bootstrap-css#3.x" data-semver="3.2.0" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
<link data-require="bootstrap-css#3.x" data-semver="3.2.0" rel="stylesheet" href="http://www.owlgraphic.com/owlcarousel/owl-carousel/owl.carousel.css" />
<link data-require="bootstrap-css#3.x" data-semver="3.2.0" rel="stylesheet" href=" http://www.owlgraphic.com/owlcarousel/owl-carousel/owl.theme.css" />
<script data-require="angular.js#*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<script data-require="ui-bootstrap#0.10.0" data-semver="0.10.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>
<link href="style.css" rel="stylesheet" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="script.js"></script>
<script src="http://www.owlgraphic.com/owlcarousel/owl-carousel/owl.carousel.js"></script>
</head>
<body>
<div id="owl-demo">
<div class="item"><p>one</p></div>
<div class="item"><p>two</p></div>
<div class="item"><p>three</p></div>
<div class="item"><p>four</p></div>
</div>
</body>
</html>
You can use a directive like this:
app.directive('owlCarousel', function() {
return {
restrict: 'A',
scope: {
owlOptions: '='
},
link: function(scope, element, attrs) {
$(element).owlCarousel(scope.owlOptions);
}
};
});
And on the HTML add it as an attribute:
<div owl-carousel owl-options="owlOptions">
...
</div>
Demo
Here is my general solution. This works with ngrepeat and with refresh data of the scope. The trick is add a directive for the last item, so the init will be fired when the last item is in the dom.
<div owl-slides-count="3" owl-carousel="">
<div ng-repeat="post in posts" owl-carousel-item="">
...
</div>
</div>
... the js
.directive('owlCarousel', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.initCarousel = function () {
// hacky ondomready
$timeout(function hackyDomReady() {
// if is already initialized destroy and re create it
// $(element).data().owlCarousel <- owl 2
if ($(element).data('owlCarousel')) { // <- owl 1
// $(element).trigger('destroy.owl.carousel'); // <- owl 2
$(element).data('owlCarousel').destroy();// <- owl 1
}
$(element).owlCarousel({
autoPlay: 10000,
navigation: true,
items: attrs.owlSlidesCount
});
});
};
}
};
}])
.directive('owlCarouselItem', [function () {
return {
restrict: 'A',
transclude: false,
link: function (scope, element) {
if (scope.$last) {
scope.initCarousel();
}
}
};
}])
I have created a directive which should be able to call a function in a controller and use a variable in controller and directive.
I can not figure out how to call the callback.
I can not figure out to enable two way data binding on my directive scope variable.
Here is the plnk: http://plnkr.co/edit/T1bMYUnkPeZmHHd05SCI?p=preview
html
<!DOCTYPE html>
<html data-ng-app="App">
<head>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body data-ng-controller="BodyCtrl">
<h1>{{title}}</h1>
<div class="container">
<div class="dateselector" data-ng-select="select" data-ng-refresh="refresh()"></div>
</div>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular-route.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="script.js"></script>
</body>
</html>
html template
<div class="row">
<div class="col-md-3 col-sm-3">
<select class="form-control" ng-model="select" ng-options="p for p in possibilities"></select>
</div>
<div class="col-md-3 col-sm-3">
<button type="button" class="btn btn-default">Refresh</button>
</div>
</div>
javascript
var app = angular.module('App', ['ui.select']);
app.controller('BodyCtrl', ['$scope', function($scope) {
$scope.title = 'Select Directive';
$scope.select = 1;
$scope.refresh = function() {
alert("Refresh in Controller! " + $scope.select);
};
}]);
// Module
angular.module('ui.select', [])
.directive('dateselector', ['$parse', function($parse) {
var link = function ($scope, $element, $attributes) {
$scope.possibilities = [1,2,3,4,5,6];
$element.find('button').bind('click', function() {
alert('Refresh in directive!');
// How to call callback?
$scope.refresh;
});
};
return {
restrict: 'EC',
replace: true,
templateUrl: 'template.html',
scope: {
select: "=",
refresh: "&"
},
link: link
};
}]);
The basic problem is that your directive expects to see and attribute of the form some-name or data-some-name, but you specify one like this: data-ng-some-name.
Additionally, the recommended way to bind a callback to a button's click event is using ngClick.
<!-- In the VIEW -->
<div class="dateselector" data-select="select" data-refresh="refresh()"></div>
<!-- In the TEMPLATE -->
<button ... ng-click="refresh()">Refresh</button>
See, also, this modified demo.