how to use jQuery plugin (semantic-ui) in angularJS directive? - javascript

I use semantic-ui in my project, the pulgin is checkbox
someone say if use jQ plugin, you must use it in angular directive
but it doesn't work
the checkbox of semantic-ui setting in semantic-ui API document, you must set this to init checkbox
$('.ui.checkbox').checkbox();
I try to change it to angular like this:
app.html
<div class="ui animate list">
<div class="item ui toggle checkbox" todo-checkbox ng-repeat="item in day track by $index">
<input type="checkbox">
<label ng-bind="item.content"></label>
</div>
</div>
and this is directive in angularjs file
todoApp.directive('todoCheckbox', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
$(elem).checkbox();
}
};
});
but it doesn't work in my project. Why?

You're close. elem is the element of the directive. In this case it is
<div class="item ui toggle checkbox" todo-checkbox ng-repeat="item in day track by $index">
<input type="checkbox">
<label ng-bind="item.content"></label>
</div>
Now, if we use find to help us locate the input field within the elem, then we can select the input field and run the checkbox method.
todoApp.directive('todoCheckbox', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
angular.forEach(elem.find( "input" ), function(inputField) {
inputField.checkbox();
}
}
};
});

A bit late to the party but you should be able to just move the todo-checkbox to the input tag (same with the semantic ui specific attributes)

Try
angular.element(elem).checkbox();
instead of
$(elem).checkbox();

Related

ng-bind-html renders data as HTML but ignores children elements

I'm working on this function that generates HTML based on user input and I can render it as proper HTML inside a list item (instead of a string version) using ng-bind-as-html.
The only problem is that it doesn't render the span tag that is also a child element in the li tag. I'm an Angular n00b and could use any insight ya got.
The code below allows me to have my functions output as proper HTML, which is nice, but I need that span tag to show up as it allows my user to copy the contents of the text.
Basically, I can either rewrite without ng-bind-html and have the span render appropriately, or I can have my HTML output render and not get the span tag. I'm stuck with one or the other and not both... and I want both. Classic.
Thanks for your help!
<li
class="entry"
ng-repeat="entry in output track by $index"
ng-mouseenter="onEnter()"
ng-bind-html="entry">
{{entry}}
<span
class="copy"
ng-click="copyData(entry)"
ng-mouseenter="onEnter()">
{{message}}
</span>
</li>
You can create a custom directive to achieve this with transclude and ng-transclude as below.
Documentation for ng-transclude
var app = angular.module('app', []);
app.controller('TestController', ['$scope', function($scope) {
$scope.message = 'You are welcome!';
$scope.output = ['<h1>Hello user</h1>'];
}]);
app.directive('bindHtml', ['$sce', function($sce) {
return {
restrict: 'A',
transclude: true,
template: '<span><span ng-bind-html="html"></span><span ng-transclude></span></span>',
link: function (scope, element, attrs) {
scope.html = $sce.trustAsHtml(scope.$eval(attrs.bindHtml));
}
};
}]);
angular.bootstrap(document, ['app']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="TestController">
<li
class="entry"
ng-repeat="entry in output track by $index"
ng-mouseenter="onEnter()"
bind-html="entry">
<span
class="copy"
ng-click="copyData(entry)"
ng-mouseenter="onEnter()">
{{message}}
</span>
</li>
</div>

How to include multiple divs in a single directive?

I am trying to include multiple div's in a single directive.But the directive works on only first div and it leaves the other div's inside it.
Template code:
<div actor-check-box ng-repeat="actor in actors">
<div create-connections class="actor\{{$index}}" >
<span><input class="checkbox-actor" type="checkbox" name="actor-checkbox" id="actor-checkbox\{{$index}}">\{{actor}}</span>
</div>
<div ng-repeat="activity in activities">
<div ng-if="actor == activity.id">
<div ng-repeat = "impact in activity.text" >
<div update-connections class="impact\{{$index}}actor\{{actors.indexOf(actor)}}" actor-id="actor\{{actors.indexOf(actor)}}">
<span><input class="checkbox-activity" type="checkbox" name="impact-checkbox" id="activity-checkbox\{{$index}}actor\{{actors.indexOf(actor)}}" activity-check-box>\{{impact}}</span>
</div>
<div ng-repeat="feature in features">
<div ng-if="actor == feature.id && impact == feature.key">
<div feature-connection ng-repeat = "feature in feature.text" class="feature\{{$index}}" activity-id="impact\{{activity.text.indexOf(impact)}}actor\{{actors.indexOf(actor)}}" id="">
<span><input class="checkbox" type="checkbox" name="impact-checkbox" id="" >\{{feature}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Directive Code:
angular.module('mainModule').directive('actorCheckBox', function($interval) {
return {
restrict: 'EA',
/*transclude: true,*/
link: function (scope, element, attrs, ctrl) {
scope.$watch('ngModel', function(newValue){
/*alert(newValue);*/
console.log(element.find('input[type="checkbox"]'));
/*console.log(element.find('input[class="checkbox-actor"]'));*/
console.log(element.find('input[class="checkbox-activity"]'));
console.log(attrs);
});
}
}
});
Output In console:
[input#actor-checkbox0.checkbox-actor, prevObject: o.fn.init[1], context: div.ng-scope, selector: "input[type="checkbox"]"]
[input#actor-checkbox1.checkbox-actor, prevObject: o.fn.init[1], context: div.ng-scope, selector: "input[type="checkbox"]"]
[input#actor-checkbox2.checkbox-actor, prevObject: o.fn.init[1], context: div.ng-scope, selector: "input[type="checkbox"]"]
So the problem is I have 3 div's and directive is applied on the first div
and 2 more div is inside the main div with checkbox. When the directive is called console only shows the checkbox element in main div not of other 2 div's. Adding the console out from directive as well:
If I inlude transclude: true it removes all the earlier directives on the element and page goes blank.
It's not happening because ng-repeat creates separate scopes for itself. You need to include in on the divs as well or modify your directive to not use isolated scopes.

why if I use ng-repeat, the jQ plugin doesn't work, if don't use, it work normal?

I use semantic-ui in angular
when I don't use ng-repeat in html, jQuery plugin work normal
like this
html
<div class="ui animate list">
<div class="item ui toggle checkbox" todo-checkbox>
<input type="checkbox">
<label>222</label>
</div>
</div>
directive.js
todoApp.directive('todoCheckbox', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.checkbox();
}
};
});
if my code like this, The checkbox plugin work normal
but if I use ng-repeat in html, elem.checkbox()inoperative like this
<div class="ui animate list">
<div class="item ui toggle checkbox" todo-checkbox ng-repeat="item in day track by $index">
<input type="checkbox">
<label ng-bind="item.content"></label>
</div>
</div>
the directive.js is same as abve
if use ng-repeat, app isn't work,
why?
how can I fixed this?

AngularJS directive to add other directives not functional

I am trying to construct a directive that adds form groups to a particular div. I'm attempting doing this by binding a directive to a button in my html. My application is VERY simple as this is all I'm trying to do at the moment. Similar to this fiddle Anyway, my app initiates fine and the home controller is included. Also I get 200 status codes on the inclusion of my directive, and my code throws no errors. Here is my html:
<form id="addFields">
<div class="row">
<div class="col-xs-4">
</div>
<div class="col-xs-4 text-center">
<div addInputFieldsButton></div>
<input id="fieldName" placeholder="Enter field name:"></input>
<button id="addFieldBtn" addInputFields><span class="glyphicon glyphicon-plus"></span></button>
</div>
<div class="col-xs-4">
</div>
</div>
</form>
<div id="reviewFields">
</div>
Notice I am attempting both to add the button that is supposed to add input fields, and just bind the directive that adds input fields to an existing button as an attribute. Neither work.
addInputFields directive:
(function () {
angular.module('reviewModule')
.directive('addInputFields', addInputFields);
addInputFields.$inject = ['$log'];
function addInputFields ($log) {
return function (scope, element, attr) {
$log.debug('binding click event to add review button now.');
element.bind('click', function ($compile) {
$log.debug('button bound.');
angular.element(document.getElementById('reviewFields')).append($compile("<button>YOU MADE A BUTTON, COOL BRO</button>")(scope));
});
}
}
})()
and my directive for attempting to add a button that has the above binding:
(function () {
angular.module('reviewModule')
.directive('addInputFieldsButton', addInputFieldsButton);
addInputFieldsButton.$inject = ['$log'];
function addInputFieldsButton ($log) {
return {
restrict : 'E',
template : '<input id="fieldName" placeholder="Enter field name:"></input>\
<button id="addFieldBtn" addInputFields><span class="glyphicon glyphicon-plus"></span></button>'
};
};
})()
I copied the fiddle almost exactly, and really have no idea why nothing is happening while attempting to use either of these directives. Forgive me if my error is obvious, I am still pretty new to AngularJS.
I believe your second directive is not defined correctly on UI, it should be - separated with smaller case add-input-fields instead of addInputFields.
Code
(function () {
angular.module('reviewModule')
.directive('addInputFieldsButton', addInputFieldsButton);
addInputFieldsButton.$inject = ['$log'];
function addInputFieldsButton ($log) {
return {
restrict : 'E',
template : '<input id="fieldName" placeholder="Enter field name:"></input>\
<button id="addFieldBtn" add-input-fields><span class="glyphicon glyphicon-plus"></span></button>'
//^^^^^^^^^^^^^^^here is change
};
};
})()

Directive link function does not have access to the entire template DOM

I have a directive which has a template that recursively include a template. In my directive link function, I am unable to get the complete DOM with a selector.
Here is my directive. Notice that my directive try to call dropdown() function on all .ui.dropdown divs constructed so nested dropdown will be activated.
.directive("floatingDropdown", function() {
return {
restrict: 'E',
templateUrl: "scripts/Ui/FloatingDropdown.html",
replace: true,
scope: {
uiClass: '#',
model: '=ngModel',
optionTree: '='
},
link: function(scope, elem, attrs) {
scope.elemClass = scope.uiClass || "ui floating dropdown icon button";
$(elem).dropdown();
$(elem).find(".ui.dropdown").dropdown();
}
}
})
The scripts/Ui/FloatingDropdown.html contains a nested include. This creates multiple levels of dropdowns
<div class="{{elemClass}}">
<script type="text/ng-template" id="node_template.html">
<div class="ui dropdown" ng-if="option.options">
<span ><i class="dropdown icon"></i> {{option.value}}</span>
<div class="menu" ng-if="data.options">
<div class="item" ng-repeat="option in data.options" ng-include="'node_template.html'"></div>
</div>
</div>
<span ng-if="!option.options" ng-click="model=option">{{option}}</span>
</script>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" ng-repeat="option in optionTree.options" ng-include="'node_template.html'">
</div>
</div>
</div>
My problem is $(elem).find(".ui.dropdown") will not find the recursively generated divs by ng-include
By attempting to do DOM manipulation in a directive's link() method like that, you're trying to query/modify a part of the DOM that hasn't been rendered yet.
You need to defer those jquery calls until later. You can do this using:
$scope.$evalAsync(function() {
// DOM code
});
or
$timeout(function() {
// DOM code
}, 0);
Using $evalAsync will run the expression during the next $digest cycle, will allow you to modify HTML before it's rendered in the browser. Using $timeout will wait until all $digest cycles are complete.

Categories

Resources