AngularJS. Multiple select JQuery plugin - angularjs

What is proper way to implement this bootstrap select plugin (http://silviomoreto.github.io/bootstrap-select/) to angular. I have put it in the directive:
App.directive('selectmultiple', [function(){
return function(scope, element, attributes){
element = $(element[0]);
element.selectpicker({
})
}
})
But it's not working. If I write in Chrome console $('.selectpicker').selectpicker({}) - proper combobox appear (opened), but a can't close it.
Thanks

I created a working example in jsfiddle. The way I found to use bootstrap-select plugin with angular was:
HTML:
<div ng-app="myApp">
<div ng-controller="MyCntrl">
<select ng-model='color' multiple ng-multiple="true" ng-options='c.name for c in colors' select-multiple></select>
</div>
</div>
Controller:
angular.module('myApp.controllers', [])
.controller('MyCntrl', ['$scope', function($scope) {
$scope.colors = [
{name:'black'},
{name:'white'},
{name:'red'},
{name:'blue'},
{name:'yellow'}
];
$scope.color = $scope.colors[2]; // red
}]);
Directive:
angular.module('myApp.directives', [])
.directive('selectMultiple', function() {
return function(scope, element, attributes){
element.selectpicker({});
scope.$watch(function () {
return element[0].length;
}, function () {
element.selectpicker('rebuild');
});
// Watch for any changes from outside the directive and refresh
scope.$watch(attributes.ngModel, function () {
element.selectpicker('refresh');
});
}
});
I hope it helps you ;)

Related

angularjs click event inside the ngBindHtml directive

I have an angularjs sample code snippet here where i can bind the html tags using ng-bind-html directive. But how can I include some other tags like angularjs ng-click, id tag etc inside ngBindHtml directive like
Test
My sample code is here:
var app = angular.module("myApp", ['ngSanitize']);
app.controller("myCtrl", function($scope) {
$scope.myText = "<a href='#' ng-click='someFunction()'>Test</a>";
$scope.someFunction = function(){
alert("Link Clicked");
};
});
FYI, the data is loaded dynamically from server side script and i have to use ng-bind-html inside ng-repeat directive and i have to pass respective id's to click events something like ng-click="myFunction(x.id)" as in sample 2.
As suggested #Dr Jones, you need use $compile directive.
Live example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope) {
$scope.myText = "<button ng-click='someFunction(1)'>{{text}}</button>";
$scope.text = "Test";
$scope.someFunction = function(val) {
console.log(val);
};
})
.directive('bindHtmlCompile', function($compile) {
return {
restrict: "A",
scope: {
bindHtmlCompile: "="
},
link: function(scope, elem) {
scope.$watch("bindHtmlCompile", function(newVal) {
elem.html('');
var newElem = angular.element(newVal);
var compileNewElem = $compile(newElem)(scope.$parent);
elem.append(compileNewElem);
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<h3>
Write code for test button
</h3>
<textarea cols="100" ng-model="myText"></textarea>
<div bind-html-compile="myText">
</div>
</div>
</div>

AngularJS Directive accessing controler scope

TL;DR I solved my problem. Here is plunker with 3 different solutions:
http://plnkr.co/edit/E0ErKs?p=preview
I don`t like slider1 because it stores value in $scope ( {{sliderValue}} ) and according to recommendation from Angular Style Guide we should avoid that.
I don`t like slider2 because it assumes that controler have alias vm in a view (so we create some kind of coupling between view and directive).
Solution 3 looks OK for me. Am I missing something?
How would you write differently this directive to be in complience with Angular philosophy?
INITIAL QUESTION:
I am learning angular and not everything is clear to me yet.
I found this question:
How to use jQuery in AngularJS
So I created working example:
Directive:
(function() {
'use strict';
angular.module('demoApp').directive('slider', function () {
return {
restrict: 'A',
controller: function ($scope, $element, $attrs) {
$scope.onSlide = function (e, ui) {
$scope.sliderValue = ui.value;
$scope.$digest();
};
},
link: function (scope, el, attrs) {
var options = {
value: scope.sliderValue,
slide: scope.onSlide
};
// set up slider on load
angular.element(document).ready(function () {
scope.$slider = $(el).slider(options);
});
}
}
});
})();
Controller:
(function() {
'use strict';
angular.module('demoApp').controller('DemoAppTestCtrl', DemoAppTestCtrl);
DemoAppTestCtrl.$inject = [ '$scope' ];
function DemoAppTestCtrl($scope) {
$scope.sliderValue = 10;
}
})();
And Html page:
<div ng-controller="DemoAppTestCtrl as vm">
Value: {{sliderValue}}
<div slider></div>
</div>
Everything works fine. Angular put slider in place of <div slider> and I can move it and I see changing values in {{sliderValue}}.
Then I found this Angular Style Guide
https://github.com/johnpapa/angular-styleguide
In chapter about controllers they recommend to use controllerAs with vm syntax (because $scope is bad or something).
Ex:
function CustomerController() {
var vm = this;
vm.name = {};
vm.sendMessage = function() { };
}
So I changed my controller to this:
(function() {
'use strict';
angular.module('demoApp').controller('DemoAppTestCtrl', DemoAppTestCtrl);
DemoAppTestCtrl.$inject = [ ];
function DemoAppTestCtrl($scope) {
var vm = this;
vm.sliderValue = 10;
}
})();
And Html page to:
<div ng-controller="DemoAppTestCtrl as vm">
Value: {{vm.sliderValue}}
<div slider></div>
</div>
But i don`t know how to fix my directive.
I want the same functionality, when i move the slider i want to set vm.sliderValue inside controler instead $scope.sliderValue inside scope.
EDIT1:
I was able to make it work by adding $scope.vm inside controller and link functions (because my controller sits in scope as vm). But I am not sure if this is right way to do it, because now my directive assume that there is controller in scope under $scope.vm alias.
Is this bad design or normal way of doing things in Angular ?
(function () {
'use strict';
angular
.module('demoApp')
.directive('slider', slider);
slider.$inject = [ ];
function slider() {
return {
restrict: 'A',
controller: function ($scope, $element, $attrs) {
$scope.vm.onSlide = function (e, ui) {
$scope.vm.sliderValue = ui.value;
$scope.$digest();
};
},
link: function (scope, el, attrs) {
var options = {
value: scope.vm.sliderValue,
slide: scope.vm.onSlide
};
// set up slider on load
angular.element(document).ready(function () {
scope.$slider = $(el).slider(options);
});
}
}
}
})();
EDIT2:
I was able to create working Plunker with 3 different versions:
http://plnkr.co/edit/E0ErKs?p=preview
Use scope: false as a option in the directive.
http://www.undefinednull.com/2014/02/11/mastering-the-scope-of-a-directive-in-angularjs/
try something like this:
angular.module('myApp', []);
angular.module('myApp').controller('DemoAppTestCtrl', DemoAppTestCtrl);
function DemoAppTestCtrl() {
var vm = this;
vm.sliderValue = 10;
}
angular.module('myApp').directive('slider', sliderDirective );
function sliderDirective() {
return {
restrict: 'A',
controller: sliderController,
controllerAs: 'sliderCtrl',
template: "<p>{{sliderCtrl.test}}</p>"
}
}
function sliderController() {
var vm = this;
vm.test = "hello";
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="DemoAppTestCtrl as vm">
Value: {{vm.sliderValue}}
<div slider></div>
</div>
</div>

angular directives inside ng-bind-html is not evluated

This is a subsequent question to this post .
I have an ng-attr-title used in the html injected using ng-bind-html which is not working ie) the title is not formed in the DOM element hence on hovering the tooltip is not formed.here is my code
myApp.controller("MyCtrl",function($scope) {
$scope.tl="this is title";
$scope.level = "<span ng-attr-title='{{tl}}'><b>data</b></span>";
});
Problem is illustrated in the Jsfiddle
You have to use $compile service to achieve this.
JS:
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller("MyCtrl", function($scope){
$scope.tl="this is title";
$scope.level = "<span ng-attr-title='{{tl}}'><b>data</b></span>";
});
myApp.directive('compileHtml', compileHtml);
function compileHtml($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(function () {
return scope.$eval(attrs.compileHtml);
}, function (value) {
element.html(value);
$compile(element.contents())(scope);
});
}
};
}
HTML:
<div ng-controller="MyCtrl" id="tableForVxp" class="dataDisplay2">
<span compile-html="level" ></span>
</div>
This compileHtml directive will compile your HTML template against your $scope.
I found that the other answers have problems and that the following directive works, and can be installed with bower.
https://github.com/incuna/angular-bind-html-compile
ng-bind-html will inject html as string. It will not compile it.
check http://plnkr.co/edit/M80zp3o4FIODIXFWVAuM?p=preview
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.val = 'patel';
$scope.myHTML =
'I am an <code>HTML</code>string with ' +
'links! and other <em>stuff</em> {{val}}';
}]);
You need custom directive which compiles your html and injects it into your element.
Use following directive
module.directive('bindHtmlCompile', ['$compile', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(function () {
return scope.$eval(attrs.bindHtmlCompile);
}, function (value) {
element.html(value);
$compile(element.contents())(scope);
});
}
};
}]);
This is a normal behaviour of ng-bind-html. Generally, the controller's code should not have HTML markup - move it to template and controls it's visibility with ng-show/ng-hide instead.
However, you still can do that if you want, just use $compile service. See example here: https://docs.angularjs.org/api/ng/service/$compile

AngularJS: Using directives within dynamic HTML

I'm attempting to build dynamic HTML strings which include a directive that reacts to changes in a scope variable. If I build the strings statically then my $watch works properly, but if the strings are dynamic then the $watch never fires.
I am sure the answer lies somewhere in use of $compile, and I have studied numerous examples, but I can't seem to make them work for my specific needs.
Is this possible?
My plunkr, which demonstrates referencing sentences with a superscript tag.
index.html
<body ng-controller="MainCtrl">
<h3>Static Example</h3>
<div>Humpty Dumpty sat<ref><sup>1</sup></ref> on a wall.</div>
<div>Humpty Dumpty had a great<ref><sup>2</sup></ref> fall.</div>
<h3>Dynamic Example</h3>
<div ng-repeat="item in dynamic">
<span ng-bind-html="item | to_trusted"></span>
</div>
<br>
<input type="checkbox" ng-click="sup = !sup"> hide/show
</body>
app.js
var app = angular.module('app', [])
.filter('to_trusted', ['$sce', function($sce) {
return function(text) {
return $sce.trustAsHtml(text);
};
}]);
app.controller('MainCtrl', function($scope) {
$scope.sup = true;
$scope.dynamic = ["Humpty Dumpty sat on a wall.<ref><sup>1</sup></ref>",
"Humpty Dumpty had a great fall.<ref><sup>2</sup></ref>"];
});
app.directive('sup', function($compile) {
return {
restrict: 'E',
link: function(scope, element) {
scope.$watch('sup', function() {
element.css({ display: scope.sup ? 'inline' : 'none' });
});
}
}});
You have to change your directive like below.
app.directive('compile', ['$compile', function ($compile) {
return function (scope, element, attrs) {
scope.$watch(
function (scope) {
return scope.$eval(attrs.compile);
},
function (value) {
element.html(value);
$compile(element.contents())(scope);
}
);
};
}]);
then use it in html like this.
<h3>Dynamic Example</h3>
<div ng-repeat="item in dynamic">
<span compile="item"></span>
</div>
Demo code

AngularJS: include not working from a custom directive

I have a custom directive and I would like to use it to include an html content to the document after clicking on it.
Plunker: http://plnkr.co/edit/u2KUKU3WgVf637PGA9A1?p=preview
JS:
angular.module("app", [])
.controller("MyController", function ($scope) {
})
.directive('addFooter', ['$compile', '$rootScope', function($compile, $rootScope){
return {
restrict: 'E',
template: '<button>add footer</button>',
controller: 'MyController',
link: function( scope, element, attrs, controller) {
element.bind( "click", function() {
scope.footer = "'footer.html'";
})}
};
}])
HTML:
<body ng-app="app">
<script type="text/ng-template" id="footer.html">
FOOTER
</script>
<div ng-controller="MyController">
<add-footer></add-footer>
<div ng-include="footer"></div>
</div>
</body>
Not sure why it is not working, as it worked fine before it was moved into the directive. Outside the directive, I was also referencing to $scope.footer with some link. I tried using $rootScope, but also no effect. Any tips please?
First. Remove unnecessary quote symbols:
element.bind( "click", function() {
scope.footer = "footer.html"; // not "'footer.html'"
});
Second. You should notify angularjs that you have asynchronously updated scope values:
element.bind("click", function() {
scope.$apply(function() {
scope.footer = "footer.html";
});
});
Or like that
element.bind("click", function() {
scope.footer = "footer.html";
scope.$apply();
});

Resources