Using jquery from angular directive does not work - javascript

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();

Related

add custom directive in element programmatically instead of HTML

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>

use jQuery.matchHeight from Angular directive

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.

uibCollapse nested in an directive element won't work,

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

How do I access this scope variable inside of isolated scope directive?

This is my situation in psuedo code
<div data-ng-controller="test">
<div isolated-directive>
<select ng-model="testControllerScopeVar">...</select>
</div>
<div ng-if="some condition that uses testControllerScopeVar"></div>
</div>
This worked perfectly before I added isolated-directive, now that it is added (scope: true) the ng-if no longer works because I think it is getting eat up inside of the directive.
What is the most efficient way to get this working without touching the structure of the html and isolated-directive?
Well it seems once I know the solution, it is so simple
<div data-ng-controller="test as testCtrl">
<div isolated-directive>
<select ng-model="testCtrl.testControllerScopeVar">...</select>
</div>
<div ng-if="testCtrl.testControllerScopeVar == 'whatever'"></div>
</div>
ControllerAs allows me to specifically access the right scope and works perfectly, thanks all for your time and input
One approach is to map the controller variable into your isolated scope and attach the isolated scope variable to your internal ng-model.
So your HTML would look like this:
<div data-ng-controller="test">
<div isolated-directive="testControllerScopeVar">
<select ng-model="isolatedScopeVar">...</select>
</div>
<div ng-if="some condition that uses testControllerScopeVar"></div>
</div>
And your directive declaration would look like this:
app.directive('isolatedDirective', function () {
return {
scope: {
isolatedScopeVar: '=isolatedDirective'
}
};
});
You can try jQuery to get the value and assign it to a new scope variable. Something like this
HTML
<div ng-app="TestApp">
<div data-ng-controller="test">
<div isolated-directive>
<input id="isolatedVar" ng-model="testControllerScopeVar" />
</div>
<div>
{{isolatedVar}}
</div>
</div>
</div>
JS
var app = angular.module('TestApp', []);
app.controller('test', function($scope) {
var element = angular.element(document.querySelector('#isolatedVar'));
element.bind('keyup', function() {
$scope.isolatedVar = element.val();
console.log($scope.isolatedVar);
$scope.$watch('isolatedVar', function() {});
});
});
app.directive('isolatedDirective', function() {
return {
scope: true
};
});
Working fiddle https://jsfiddle.net/kavinio/yzb8ouzd/1/

Angularjs show hide css issue

I had a hard issue figuring out on how to hide and show icon/text with angular code. I am completely new to angular and tried hard on the below fiddle code. How do I hide + or minus icon with .closest in such dom scenarios.
<div ng-controller="MyCtrl">
{{name}}
<div data-toggle="collapse" aria-expanded="true" data-target="#list-item-line-0" id="expandCollapseChild" ng-click="addExpandCollapseChildIcon()">
<div>
<div>
<label>
<div>
<span class="icon-expand">-</span>
<span class="icon-collapse">+</span>
</div>
<div>
Click me to hide minus icon
</div>
</label>
</div>
</div>
</div>
</div>
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.addExpandCollapseChildIcon = function() {
alert('');
if (angular.element('#expandCollapseChild').hasClass('collapsed')) {
angular.element(this).closest('.icon-collapse').css('display', 'none');
} else {
if (angular.element('#expandCollapseChild').hasClass('collapsed')) {
angular.element(this).closest('.icon-collapse').css('display', 'block');
}
}
}
In Angular, this is the wrong approach. You shouldn't actually show or hide elements inside the controller. That's applying a jQuery style (working directly on the DOM) to Angular.
In Angular, you'd use something like ng-if, ng-show or ng-class, all of which can link back to a property on the scope object that is accessible via the controller.
Here are some examples:
<div ng-if="myProp === 'ShowMe'">
<div ng-show="myProp === 'ShowMe'">
<div ng-class="{myCssClass: myProp === 'ShowMe'">
Inside your controller, you'd have something like this:
function MyCtrl($scope) {
$scope.myProp = 'ShowMe';
$scope.addExpandCollapseChildIcon = function(newPropValue) {
$scope.myProp = newPropValue;
}
}
Here's some links to documentation on ng-if, ng-show and ng-class:
https://docs.angularjs.org/api/ng/directive/ngIf
https://docs.angularjs.org/api/ng/directive/ngShow
https://docs.angularjs.org/api/ng/directive/ngClass
AngularJS has a bunch of angulary ways of doing things, your question for example might look like this:
var app = angular.module("app", []);
app.controller("ctrl", function($scope) {
$scope.collapsed = true;
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl">
<span ng-bind="collapsed ? '+' : '-'"></span>
</div>
</div>
It watches a model and changes it's appearance based on that model using the ternary operator within ng-bind.
The way you defined your app and controller was incorrect. There's a bunch of different ways to do this as you can see from the answers.
I took this approach:
<div ng-app='myApp' ng-controller="MyCtrl">
{{name}}
<div>
<div>
<div>
<label>
<div>
<span ng-show='(collapsed != false)' class="icon-expand">-</span>
<span ng-show='(collapsed == false)' class="icon-collapse">+</span>
</div>
<div ng-click='collapsed = !collapsed'>
Click me to hide minus icon
</div>
</label>
</div>
</div>
</div>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope) {
$scope.name = 'Superhero';
$scope.collapsed = false;
});
</script>
Create a scoped variable that indicated whether or not it is collapsed . Then change that variable and the ng-shows will react.

Categories