directive function calling multiple times in angularjs - angularjs

I have created directive in anguular js to resize image in angularjs.
Here is the code of directive :
app.directive('resize1', function ($window) {
return {
restrict: 'A',
replace: true,
scope: {
params: '&',
path: '=',
siteurl: '='
},
link: function($scope, element, attrs) {
$scope.resizeImage = function() {
var size = 0;
var width = angular.element($window).width();
src = $(element).attr('src');
if (src != null || src != '') {
var url = parse_url(src).query;
var path = parse_url(src).path;
var str = url.split('&');
var link = '?';
$.each(str, function(index, value) {
pair = value.split('=');
if (pair[0] != 'h' && pair[0] != 'w') {
link = link + value + '&';
}
});
if (width >= 960) {
size = $scope.$eval($scope.params).gt960;
newWidth = size.w;
newHeight = size.h;
} else if (width < 960 && width >= 480) {
size = $scope.$eval($scope.params).bt480960;
newWidth = size.w;
newHeight = size.h;
} else {
size = $scope.$eval($scope.params).lt480;
newWidth = size.w;
newHeight = size.h;
}
link = link + 'h=' + newHeight + '&w=' + newWidth;
$(element).attr('src', path + link);
$(element).attr('ng-src', path + link);
$(element).closest('div.spinner').css({
'height' : newHeight,
'width' : newWidth,
'margin' : '0px auto'
});
}
};
angular.element($window).bind('resize', function() {
$scope.resizeImage();
});
$scope.$watch('path', function (){
//alert('df');
$scope.resizeImage();
});
}
}
});
and my html is :
<div class="list-view" ng-hide="productDetail == null">
<div class="list-view-img">
<div class="spinner">
<img resize1
ng-src="{{siteurl}}thumbnails/index?file={{path}}&h=200&w=200"
params="{lt480: {h: 300,w: 300}, bt480960: {h: 450,w: 450}, gt960: {h: 940,w: 940}}"
path="paths.products.primary_image + productDetail.primary_image"
siteurl="siteUrl"
/>
</div>
</div>
</div>
Now the problem is its working fine but directive function is called 3 times..
Can anybody tell me what can be wrong ? why it is called thrice though i have called it once ?

Related

How to destroy and reinitialize angular directive -- on window resize?

I've tried invoking the directive below again on $(window).resize, and adding scope.$digest to it, but the directive does not respond.
I'm attempting to load responsive width and height (which are properties of scope.viewport and scope.boundary) to the options: boundary / viewport width and height -- on resize.
What is the proper way to accomplish this?
angular.module('ngCroppie', []).directive('ngCroppie', [
function ($compile) {
return {
restrict: 'AE',
scope:{
src: '=',
viewport: '=',
boundry: '=',
type: '#',
zoom: '#',
mousezoom: '#',
update: '=',
ngModel: '='
},
link: function(scope, elem, attr) {
// defaults
if(scope.viewport == undefined){
scope.viewport = {w: null, h: null}
}
if(scope.boundry == undefined){
scope.boundry = {w: null, h: null}
}
// catches
scope.viewport.w = (scope.viewport.w != undefined) ? scope.viewport.w : 300;
scope.viewport.h = (scope.viewport.h != undefined) ? scope.viewport.h : 300;
scope.boundry.w = (scope.boundry.w != undefined) ? scope.boundry.w : 400;
scope.boundry.h = (scope.boundry.h != undefined) ? scope.boundry.h : 400;
// viewport cannot be larger than the boundaries
if(scope.viewport.w > scope.boundry.w){ scope.viewport.w = scope.boundry.w }
if(scope.viewport.h > scope.boundry.h){ scope.viewport.h = scope.boundry.h }
// convert string to Boolean
var zoom = (scope.zoom === "true"),
mouseZoom = (scope.mousezoom === "true");
// define options
var options = {
viewport: {
width: scope.viewport.w,
height: scope.viewport.h,
type: scope.type || 'square'
},
boundary: {
width: scope.boundry.w,
height: scope.boundry.h
},
showZoom: zoom,
mouseWheelZoom: mouseZoom,
}
if (scope.update != undefined){
options.update = scope.update
}
// create new croppie and settime for updates
var c = new Croppie(elem[0], options);
var intervalID = window.setInterval(function(){
c.result('canvas').then(function(img){
scope.$apply(function(){
scope.ngModel = img
})
})
}, 250);
scope.$on("$destroy",
function( event ) {
clearInterval(intervalID);
}
);
// respond to changes in src
scope.$watch('src', function(newValue, oldValue) {
if(scope.src != undefined){
c.bind(scope.src);
c.result('canvas').then(function(img){
scope.$apply(function(){
scope.ngModel = img
})
})
}
})
}
};
}
]);
Here's my updated code. Now, my problem is that it keeps making a new image (that is correctly resized). I cannot figure out how to delete the initial image which needs to be replaced:
function croppieJs (){ !function(t,e){"function"==typeof define&&define.amd?define(["exports","b"],e):"object"==typeof exports&&"string"!=typeof exports.nodeName?e(exports,require("b")):e(t.commonJsStrict={},t.b)}(this,function(t,e){function n(t){if(t in j)return t;for(var e=t[0].toUpperCase()+t.slice(1),n=X.length;n--;)if(t=X[n]+e,t in j)return t}function r(t){t=t||{};for(var e=1;e<arguments.length;e++){var n=arguments[e];if(n)for(var o in n)n.hasOwnProperty(o)&&("object"==typeof n[o]?t[o]=r({},n[o]):t[o]=n[o])}return t}function o(t,e,n){var r;return function(){var o=this,i=arguments,s=function(){r=null,n||t.apply(o,i)},a=n&&!r;clearTimeout(r),r=setTimeout(s,e),a&&t.apply(o,i)}}function i(t){if("createEvent"in document){var e=document.createEvent("HTMLEvents");e.initEvent("change",!1,!0),t.dispatchEvent(e)}else t.fireEvent("onchange")}function s(t,e,n){if("string"==typeof e){var r=e;e={},e[r]=n}for(var o in e)t.style[o]=e[o]}function a(t){var e=t.points,n=document.createElement("div"),r=document.createElement("img"),o=e[2]-e[0],i=e[3]-e[1];return n.classList.add("croppie-result"),n.appendChild(r),s(r,{left:-1*e[0]+"px",top:-1*e[1]+"px"}),r.src=t.url,s(n,{width:o+"px",height:i+"px"}),n}function u(t,e){var n=e.points,r=n[0],o=n[1],i=n[2]-n[0],s=n[3]-n[1],a=e.circle,u=document.createElement("canvas"),l=u.getContext("2d"),c=i,p=s;return e.outputWidth&&e.outputHeight&&(c=e.outputWidth,p=e.outputHeight),u.width=c,u.height=p,a&&(l.save(),l.beginPath(),l.arc(c/2,p/2,c/2,0,2*Math.PI,!0),l.closePath(),l.clip()),l.drawImage(t,r,o,i,s,0,0,c,p),u.toDataURL()}function l(t,e){var n,r=e||new Image;return n=new Promise(function(t,e){r.setAttribute("crossOrigin","anonymous"),r.onload=function(){setTimeout(function(){t(r)},1)}}),r.src=t,n}function c(){var t,e,n,r,o=this,i=["croppie-container"],a=o.options.viewport.type?"cr-vp-"+o.options.viewport.type:null;o.data={},o.elements={},t=o.elements.boundary=document.createElement("div"),n=o.elements.viewport=document.createElement("div"),e=o.elements.img=document.createElement("img"),r=o.elements.overlay=document.createElement("div"),t.classList.add("cr-boundary"),s(t,{width:o.options.boundary.width+o.options.metric,height:o.options.boundary.height+o.options.metric}),n.classList.add("cr-viewport"),a&&n.classList.add(a),s(n,{width:o.options.viewport.width+o.options.metric,height:o.options.viewport.height+o.options.metric}),e.classList.add("cr-image"),r.classList.add("cr-overlay"),o.element.appendChild(t),t.appendChild(e),t.appendChild(n),t.appendChild(r),o.element.classList.add(i),o.options.customClass&&o.element.classList.add(o.options.customClass),g.call(this),o.options.showZoom&&m.call(o)}function p(t){this.options.showZoom&&(this.elements.zoomer.value=E(t))}function m(){function t(){h.call(s),r=new I(s.elements.img),o=s.elements.viewport.getBoundingClientRect(),i=F.parse(s.elements.img)}function e(){d.call(s,{value:parseFloat(u.value),origin:r||new I(s.elements.img),viewportRect:o||s.elements.viewport.getBoundingClientRect(),transform:i||F.parse(s.elements.img)})}function n(n){var r=n.deltaY/-2e3,o=s._currentZoom+r;n.preventDefault(),t(),p.call(s,o),e()}var r,o,i,s=this,a=s.elements.zoomerWrap=document.createElement("div"),u=s.elements.zoomer=document.createElement("input");a.classList.add("cr-slider-wrap"),u.type="range",u.classList.add("cr-slider"),u.step="0.01",u.value=1,s.element.appendChild(a),a.appendChild(u),s._currentZoom=1,s.elements.zoomer.addEventListener("mousedown",t),s.elements.zoomer.addEventListener("touchstart",t),s.elements.zoomer.addEventListener("input",e),s.elements.zoomer.addEventListener("change",e),s.options.mouseWheelZoom&&(s.elements.boundary.addEventListener("mousewheel",n),s.elements.boundary.addEventListener("DOMMouseScroll",n))}function d(t){var e=this,n=t.transform,r=t.viewportRect,o=t.origin;e._currentZoom=t.value,n.scale=e._currentZoom;var i=f.call(e,r),a=i.translate,u=i.origin;n.x>=a.maxX&&(o.x=u.minX,n.x=a.maxX),n.x<=a.minX&&(o.x=u.maxX,n.x=a.minX),n.y>=a.maxY&&(o.y=u.minY,n.y=a.maxY),n.y<=a.minY&&(o.y=u.maxY,n.y=a.minY);var l={};l[B]=n.toString(),l[M]=o.toString(),s(e.elements.img,l),O.call(e),y.call(e)}function f(t){var e=this,n=e._currentZoom,r=t.width,o=t.height,i=e.options.boundary.width/2,s=e.options.boundary.height/2,a=e._originalImageWidth,u=e._originalImageHeight,l=a*n,c=u*n,p=r/2,m=o/2,d=-1*(p/n-i),f=d-(l*(1/n)-r*(1/n)),h=-1*(m/n-s),g=h-(c*(1/n)-o*(1/n)),v=1/n*p,y=l*(1/n)-v,w=1/n*m,_=c*(1/n)-w;return{translate:{maxX:d,minX:f,maxY:h,minY:g},origin:{maxX:y,minX:v,maxY:_,minY:w}}}function h(){var t=this,e=t._currentZoom,n=t.elements.img.getBoundingClientRect(),r=t.elements.viewport.getBoundingClientRect(),o=F.parse(t.elements.img.style[B]),i=new I(t.elements.img),a=r.top-n.top+r.height/2,u=r.left-n.left+r.width/2,l={},c={};l.y=a/e,l.x=u/e,c.y=(l.y-i.y)*(1-e),c.x=(l.x-i.x)*(1-e),o.x-=c.x,o.y-=c.y;var p={};p[M]=l.x+"px "+l.y+"px",p[B]=o.toString(),s(t.elements.img,p)}function g(){function t(t){t.preventDefault(),c||(c=!0,r=t.pageX,o=t.pageY,transform=F.parse(l.elements.img),window.addEventListener("mousemove",e),window.addEventListener("touchmove",e),window.addEventListener("mouseup",n),window.addEventListener("touchend",n),document.body.style[Z]="none",u=l.elements.viewport.getBoundingClientRect())}function e(t){t.preventDefault();var e=t.pageX||t.touches[0].pageX,n=t.pageY||t.touches[0].pageY,c=e-r,m=n-o,d=l.elements.img.getBoundingClientRect(),f=transform.y+m,h=transform.x+c,g={};if("touchmove"==t.type&&t.touches.length>1){var y=t.touches[0],w=t.touches[1],_=Math.sqrt((y.pageX-w.pageX)*(y.pageX-w.pageX)+(y.pageY-w.pageY)*(y.pageY-w.pageY));a||(a=_/l._currentZoom);var x=_/a;return p.call(l,x),void i(l.elements.zoomer)}u.top>d.top+m&&u.bottom<d.bottom+m&&(transform.y=f),u.left>d.left+c&&u.right<d.right+c&&(transform.x=h),g[B]=transform.toString(),s(l.elements.img,g),v.call(l),o=n,r=e}function n(){c=!1,window.removeEventListener("mousemove",e),window.removeEventListener("touchmove",e),window.removeEventListener("mouseup",n),window.removeEventListener("touchend",n),document.body.style[Z]="",h.call(l),y.call(l),a=0}var r,o,a,u,l=this,c=!1;l.elements.overlay.addEventListener("mousedown",t),l.elements.overlay.addEventListener("touchstart",t)}function v(){var t=this,e=t.elements.boundary.getBoundingClientRect(),n=t.elements.img.getBoundingClientRect();s(t.elements.overlay,{width:n.width+"px",height:n.height+"px",top:n.top-e.top+"px",left:n.left-e.left+"px"})}function y(){var t=this;w.call(t)&&t.options.update.call(t,t.get())}function w(){return this.elements.img.offsetHeight>0&&this.elements.img.offsetWidth>0}function _(){var t,e,n,r,o,a=this,u=0,l=1.5,c=1,m={},d=a.elements.img,f=a.elements.zoomer,h=new F(0,0,c),g=new I,y=w.call(a);y&&!a.data.bound&&(a.data.bound=!0,m[B]=h.toString(),m[M]=g.toString(),s(d,m),t=d.getBoundingClientRect(),e=a.elements.viewport.getBoundingClientRect(),n=a.elements.boundary.getBoundingClientRect(),a._originalImageWidth=t.width,a._originalImageHeight=t.height,a.options.showZoom&&(r=e.width/t.width,o=e.height/t.height,u=Math.max(r,o),u>=l&&(l=u+1),f.min=E(u),f.max=E(l),c=Math.max(n.width/t.width,n.height/t.height),p.call(a,c),i(f)),a._currentZoom=h.scale=c,m[B]=h.toString(),s(d,m),a.data.points.length?x.call(a,a.data.points):b.call(a),v.call(a))}function x(t){if(4!=t.length)throw"Croppie - Invalid number of points supplied: "+t;var e=this,n=t[2]-t[0],r=e.elements.viewport.getBoundingClientRect(),o=e.elements.boundary.getBoundingClientRect(),i={left:r.left-o.left,top:r.top-o.top},a=r.width/n,u=t[1],l=t[0],c=-1*t[1]+i.top,m=-1*t[0]+i.left,d={};d[M]=l+"px "+u+"px",d[B]=new F(m,c,a).toString(),s(e.elements.img,d),p.call(e,a),e._currentZoom=a}function b(){var t=this,e=t.elements.img.getBoundingClientRect(),n=t.elements.viewport.getBoundingClientRect(),r=t.elements.boundary.getBoundingClientRect(),o=n.left-r.left,i=n.top-r.top,a=o-(e.width-n.width)/2,u=i-(e.height-n.height)/2,l=new F(a,u,t._currentZoom);s(t.elements.img,B,l.toString())}function C(t,e){var n,r=this,o=[];if("string"==typeof t)n=t,t={};else if(Array.isArray(t))o=t.slice();else{if("undefined"==typeof t&&r.data.url)return _.call(r),y.call(r),null;n=t.url,o=t.points||[]}r.data.bound=!1,r.data.url=n||r.data.url,r.data.points=(o||r.data.points).map(function(t){return parseFloat(t)});var i=l(n,r.elements.img);return i.then(function(){_.call(r),y.call(r),e&&e()}),i}function E(t){return parseFloat(t).toFixed(2)}function L(){var t=this,e=t.elements.img.getBoundingClientRect(),n=t.elements.viewport.getBoundingClientRect(),r=n.left-e.left,o=n.top-e.top,i=r+n.width,s=o+n.height,a=t._currentZoom;return(a===1/0||isNaN(a))&&(a=1),r=Math.max(0,r/a),o=Math.max(0,o/a),i=Math.max(0,i/a),s=Math.max(0,s/a),{points:[E(r),E(o),E(i),E(s)],zoom:a}}function S(t){var e,n,r=this,o=L.call(r),i=t||{type:"canvas",size:"viewport"},s="string"==typeof i?i:i.type,c=i.size||"viewport";return"viewport"===c&&(e=r.elements.viewport.getBoundingClientRect(),o.outputWidth=e.width,o.outputHeight=e.height),o.circle="circle"===r.options.viewport.type,o.url=r.data.url,n=new Promise(function(t,e){"canvas"===s?l(o.url).then(function(e){t(u(e,o))}):t(a(o))})}function A(){console.warn("Croppie.refresh() is deprecated. Please use Croppie.bind() without any arguments instead. refresh() will be removed in a later release."),_.call(this)}function R(){var t=this;t.element.removeChild(t.elements.boundary),t.options.showZoom&&t.element.removeChild(t.elements.zoomerWrap),delete t.elements}function Y(t,e){this.element=t,this.options=r({},Y.defaults,e),c.call(this)}"function"!=typeof Promise&&function(){"use strict";function t(t){return"function"==typeof t||"object"==typeof t&&null!==t}function e(t){return"function"==typeof t}function n(t){return"object"==typeof t&&null!==t}function r(t){W=t}function o(t){k=t}function i(){return function(){process.nextTick(c)}}function s(){return function(){T(c)}}function a(){var t=0,e=new Q(c),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function u(){var t=new MessageChannel;return t.port1.onmessage=c,function(){t.port2.postMessage(0)}}function l(){return function(){setTimeout(c,1)}}function c(){for(var t=0;q>t;t+=2){var e=G[t],n=G[t+1];e(n),G[t]=void 0,G[t+1]=void 0}q=0}function p(){try{var t=require,e=t("vertx");return T=e.runOnLoop||e.runOnContext,s()}catch(n){return l()}}function m(){}function d(){return new TypeError("You cannot resolve a promise with itself")}function f(){return new TypeError("A promises callback cannot return that same promise.")}function h(t){try{return t.then}catch(e){return et.error=e,et}}function g(t,e,n,r){try{t.call(e,n,r)}catch(o){return o}}function v(t,e,n){k(function(t){var r=!1,o=g(n,e,function(n){r||(r=!0,e!==n?_(t,n):b(t,n))},function(e){r||(r=!0,C(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&o&&(r=!0,C(t,o))},t)}function y(t,e){e._state===$?b(t,e._result):e._state===tt?C(t,e._result):E(e,void 0,function(e){_(t,e)},function(e){C(t,e)})}function w(t,n){if(n.constructor===t.constructor)y(t,n);else{var r=h(n);r===et?C(t,et.error):void 0===r?b(t,n):e(r)?v(t,n,r):b(t,n)}}function _(e,n){e===n?C(e,d()):t(n)?w(e,n):b(e,n)}function x(t){t._onerror&&t._onerror(t._result),L(t)}function b(t,e){t._state===V&&(t._result=e,t._state=$,0!==t._subscribers.length&&k(L,t))}function C(t,e){t._state===V&&(t._state=tt,t._result=e,k(x,t))}function E(t,e,n,r){var o=t._subscribers,i=o.length;t._onerror=null,o[i]=e,o[i+$]=n,o[i+tt]=r,0===i&&t._state&&k(L,t)}function L(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r,o,i=t._result,s=0;s<e.length;s+=3)r=e[s],o=e[s+n],r?R(n,r,o,i):o(i);t._subscribers.length=0}}function S(){this.error=null}function A(t,e){try{return t(e)}catch(n){return nt.error=n,nt}}function R(t,n,r,o){var i,s,a,u,l=e(r);if(l){if(i=A(r,o),i===nt?(u=!0,s=i.error,i=null):a=!0,n===i)return void C(n,f())}else i=o,a=!0;n._state!==V||(l&&a?_(n,i):u?C(n,s):t===$?b(n,i):t===tt&&C(n,i))}function Y(t,e){try{e(function(e){_(t,e)},function(e){C(t,e)})}catch(n){C(t,n)}}function M(t,e){var n=this;n._instanceConstructor=t,n.promise=new t(m),n._validateInput(e)?(n._input=e,n.length=e.length,n._remaining=e.length,n._init(),0===n.length?b(n.promise,n._result):(n.length=n.length||0,n._enumerate(),0===n._remaining&&b(n.promise,n._result))):C(n.promise,n._validationError())}function B(t){return new rt(this,t).promise}function Z(t){function e(t){_(o,t)}function n(t){C(o,t)}var r=this,o=new r(m);if(!H(t))return C(o,new TypeError("You must pass an array to race.")),o;for(var i=t.length,s=0;o._state===V&&i>s;s++)E(r.resolve(t[s]),void 0,e,n);return o}function X(t){var e=this;if(t&&"object"==typeof t&&t.constructor===e)return t;var n=new e(m);return _(n,t),n}function j(t){var e=this,n=new e(m);return C(n,t),n}function P(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function z(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function F(t){this._id=ut++,this._state=void 0,this._result=void 0,this._subscribers=[],m!==t&&(e(t)||P(),this instanceof F||z(),Y(this,t))}function I(){var t;if("undefined"!=typeof global)t=global;else if("undefined"!=typeof self)t=self;else try{t=Function("return this")()}catch(e){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=t.Promise;(!n||"[object Promise]"!==Object.prototype.toString.call(n.resolve())||n.cast)&&(t.Promise=lt)}var O;O=Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)};var T,W,D,H=O,q=0,k=({}.toString,function(t,e){G[q]=t,G[q+1]=e,q+=2,2===q&&(W?W(c):D())}),N="undefined"!=typeof window?window:void 0,U=N||{},Q=U.MutationObserver||U.WebKitMutationObserver,J="undefined"!=typeof process&&"[object process]"==={}.toString.call(process),K="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,G=new Array(1e3);D=J?i():Q?a():K?u():void 0===N&&"function"==typeof require?p():l();var V=void 0,$=1,tt=2,et=new S,nt=new S;M.prototype._validateInput=function(t){return H(t)},M.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},M.prototype._init=function(){this._result=new Array(this.length)};var rt=M;M.prototype._enumerate=function(){for(var t=this,e=t.length,n=t.promise,r=t._input,o=0;n._state===V&&e>o;o++)t._eachEntry(r[o],o)},M.prototype._eachEntry=function(t,e){var r=this,o=r._instanceConstructor;n(t)?t.constructor===o&&t._state!==V?(t._onerror=null,r._settledAt(t._state,e,t._result)):r._willSettleAt(o.resolve(t),e):(r._remaining--,r._result[e]=t)},M.prototype._settledAt=function(t,e,n){var r=this,o=r.promise;o._state===V&&(r._remaining--,t===tt?C(o,n):r._result[e]=n),0===r._remaining&&b(o,r._result)},M.prototype._willSettleAt=function(t,e){var n=this;E(t,void 0,function(t){n._settledAt($,e,t)},function(t){n._settledAt(tt,e,t)})};var ot=B,it=Z,st=X,at=j,ut=0,lt=F;F.all=ot,F.race=it,F.resolve=st,F.reject=at,F._setScheduler=r,F._setAsap=o,F._asap=k,F.prototype={constructor:F,then:function(t,e){var n=this,r=n._state;if(r===$&&!t||r===tt&&!e)return this;var o=new this.constructor(m),i=n._result;if(r){var s=arguments[r-1];k(function(){R(r,o,s,i)})}else E(n,o,t,e);return o},"catch":function(t){return this.then(null,t)}};var ct=I,pt={Promise:lt,polyfill:ct};"function"==typeof define&&define.amd?define(function(){return pt}):"undefined"!=typeof module&&module.exports?module.exports=pt:"undefined"!=typeof this&&(this.ES6Promise=pt),ct()}.call(this);var M,B,Z,X=["Webkit","Moz","ms"],j=document.createElement("div").style;B=n("transform"),M=n("transformOrigin"),Z=n("userSelect");var P="translate3d",z=", 0px",F=function(t,e,n){this.x=parseFloat(t),this.y=parseFloat(e),this.scale=parseFloat(n)};F.parse=function(t){return t.style?F.parse(t.style[B]):t.indexOf("matrix")>-1||t.indexOf("none")>-1?F.fromMatrix(t):F.fromString(t)},F.fromMatrix=function(t){var e=t.substring(7).split(",");return e.length&&"none"!==t||(e=[1,0,0,1,0,0]),new F(parseInt(e[4],10),parseInt(e[5],10),parseFloat(e[0]))},F.fromString=function(t){var e=t.split(") "),n=e[0].substring(P.length+1).split(","),r=e.length>1?e[1].substring(6):1,o=n.length>1?n[0]:0,i=n.length>1?n[1]:0;return new F(o,i,r)},F.prototype.toString=function(){return P+"("+this.x+"px, "+this.y+"px"+z+") scale("+this.scale+")"};var I=function(t){if(!t||!t.style[M])return this.x=0,void(this.y=0);var e=t.style[M].split(" ");this.x=parseFloat(e[0]),this.y=parseFloat(e[1])};I.prototype.toString=function(){return this.x+"px "+this.y+"px"};var O=o(v,500);if(this.jQuery){var T=this.jQuery;T.fn.croppie=function(t){var e=typeof t;if("string"===e){var n=Array.prototype.slice.call(arguments,1),r=T(this).data("croppie");return"get"===t?r.get():"result"===t?r.result.apply(r,n):this.each(function(){var e=T(this).data("croppie");if(e){var r=e[t];if(!T.isFunction(r))throw"Croppie "+t+" method not found";r.apply(e,n),"destroy"===t&&T(this).removeData("croppie")}})}return this.each(function(){var e=new Y(this,t);T(this).data("croppie",e)})}}Y.defaults={viewport:{width:100,height:100,type:"square"},boundary:{width:300,height:300},customClass:"",showZoom:!0,mouseWheelZoom:!0,update:function(){}},r(Y.prototype,{bind:function(t,e){return C.call(this,t,e)},get:function(){return L.call(this)},result:function(t){return S.call(this,t)},refresh:function(){return A.call(this)},destroy:function(){return R.call(this)}}),t.Croppie=window.Croppie=Y})};
croppieJs();
/*************************
* acrCroppie
* Allen Royston
* Version: 1.0.0
* Updated 4/12/2016
*************************/
angular.module('ngCroppie', []).directive('ngCroppie', [
function ($compile, $window) {
return {
restrict: 'AE',
scope:{
src: '=',
viewport: '=',
boundry: '=',
type: '#',
zoom: '#',
mousezoom: '#',
responsive: '#',
update: '=',
metric: '#',
ngModel: '='
},
link: function(scope, elem, attr) {
// defaults
if(scope.viewport == undefined){
scope.viewport = {w: null, h: null}
}
if(scope.boundry == undefined){
scope.boundry = {w: null, h: null}
}
// catches
scope.viewport.w = (scope.viewport.w != undefined) ? scope.viewport.w : 300;
scope.viewport.h = (scope.viewport.h != undefined) ? scope.viewport.h : 300;
scope.boundry.w = (scope.boundry.w != undefined) ? scope.boundry.w : 400;
scope.boundry.h = (scope.boundry.h != undefined) ? scope.boundry.h : 400;
// viewport cannot be larger than the boundaries
if(scope.viewport.w > scope.boundry.w){ scope.viewport.w = scope.boundry.w }
if(scope.viewport.h > scope.boundry.h){ scope.viewport.h = scope.boundry.h }
// convert string to Boolean
var zoom = (scope.zoom === "true"),
mouseZoom = (scope.mousezoom === "true");
// define options
var options = {
viewport: {
width: scope.viewport.w,
height: scope.viewport.h,
type: scope.type || 'square'
},
boundary: {
width: scope.boundry.w,
height: scope.boundry.h
},
metric: scope.metric,
showZoom: zoom,
mouseWheelZoom: mouseZoom,
}
function init(){
if (scope.update != undefined){
options.update = scope.update
}
console.log('scope: ', scope)
// create new croppie and settime for updates
var c = new Croppie(elem[0], options);
var intervalID = window.setInterval(function(){
c.result('canvas').then(function(img){
scope.$apply(function(){
scope.ngModel = img
})
})
}, 250);
console.log('ccc : ', c)
scope.$on("$destroy",
function( event ) {
clearInterval(intervalID);
$(window).off('resize', function(){
responsive()});
}
);
// respond to changes in src
scope.$watch('src', function(newValue, oldValue) {
if(scope.src != undefined){
c.bind(scope.src);
c.result('canvas').then(function(img){
scope.$apply(function(){
scope.ngModel = img
})
})
}
})
};
if(scope.responsive === 'true'){
function responsive(){
console.log('responsive')
// defaults
if(scope.viewport == undefined){
scope.viewport = {w: null, h: null}
}
if(scope.boundry == undefined){
scope.boundry = {w: null, h: null}
}
// convert string to Boolean
var zoom = (scope.zoom === "true"),
mouseZoom = (scope.mousezoom === "true");
scope.width = $('.modal-md form').width()
scope.height = scope.width * .264;
console.log('width : ', scope.width);
// define options
options = {
viewport: {
width: scope.width,
height: scope.height,
type: scope.type || 'square'
},
boundary: {
width: scope.width,
height: scope.height
},
metric: scope.metric,
showZoom: zoom,
mouseWheelZoom: mouseZoom,
}
init();
};
responsive();
$(window).on('resize', function(){
scope.$digest(function(){
delete scope.$$watchers[0];
scope.$$watchersCount = scope.$$watchers.length;
});
responsive();
clearInterval();
console.log('ccc : ', c)
});
}
else{
init();
}
}
};
}
]);
I think you just need to can put all the link part of your directive in a function along with the variables you need to reinitiate and put them in a function and invoke that function on window.resize event, let me show you
angular.module('ngCroppie',[]).directive('ngCroppie','$document','$log', [
function ($compile) {
return {
restrict: 'AE',
scope:{
src: '=',
viewport: '=',
boundry: '=',
type: '#',
zoom: '#',
mousezoom: '#',
update: '=',
ngModel: '='
},
link: function(scope, elem, attr) {
function init()={
// defaults
if(scope.viewport == undefined){
scope.viewport = {w: null, h: null}
}
if(scope.boundry == undefined){
scope.boundry = {w: null, h: null}
}
// catches
scope.viewport.w = (scope.viewport.w != undefined) ? scope.viewport.w : 300;
scope.viewport.h = (scope.viewport.h != undefined) ? scope.viewport.h : 300;
scope.boundry.w = (scope.boundry.w != undefined) ? scope.boundry.w : 400;
scope.boundry.h = (scope.boundry.h != undefined) ? scope.boundry.h : 400;
// viewport cannot be larger than the boundaries
if(scope.viewport.w > scope.boundry.w){ scope.viewport.w = scope.boundry.w }
if(scope.viewport.h > scope.boundry.h){ scope.viewport.h = scope.boundry.h }
// convert string to Boolean
var zoom = (scope.zoom === "true"),
mouseZoom = (scope.mousezoom === "true");
// define options
var options = {
viewport: {
width: scope.viewport.w,
height: scope.viewport.h,
type: scope.type || 'square'
},
boundary: {
width: scope.boundry.w,
height: scope.boundry.h
},
showZoom: zoom,
mouseWheelZoom: mouseZoom,
}
if (scope.update != undefined){
options.update = scope.update
}
// create new croppie and settime for updates
var c = new Croppie(elem[0], options);
}
init();
//window resizing event
$document.bind('click', function(event) {
$log.info(event);
init()://intiating the variables again
});
var intervalID = window.setInterval(function(){
c.result('canvas').then(function(img){
scope.$apply(function(){
scope.ngModel = img
})
})
}, 250);
scope.$on("$destroy",
function( event ) {
clearInterval(intervalID);
}
);
// respond to changes in src
scope.$watch('src', function(newValue, oldValue) {
if(scope.src != undefined){
c.bind(scope.src);
c.result('canvas').then(function(img){
scope.$apply(function(){
scope.ngModel = img
})
})
}
})
}
};
}
]);
Try it out!
PS: unbind the resize event when you destroy the scope of directive, that can be done pretty much easily i guess
Did you try listening to the resize event in the link function?
link: function(scope, element, attrs) {
scope.doSomething = function() {
//example of accessing element's attribute
var width = $(element).width();
};
$window.addEventListener("resize", scope.doSomenthing);
}

Meaning of hyphen in Angular tags

I found a bit of code on Plunker which I don't understand. It's a word cloud where the cloud is added to the page with:
<tang-cloud words="words" on-click="test(word)" width="500" height="500"></tang-cloud>
This is some how picked up by Angular. What I don't understand is I can find no references to "tang-cloud" in the rest of the code. Various "tangcloud" but nothing with a hyphen.
I'm totally new to Angular, I've stumbled across another case where this seems to happen, but all the tutorial cases I've seen would have used "tangcloud". If I remove the hyphen it stops working, so I must just be missing something simple.
Thank you
It's a directive. Since HTML is case-insensitive, angular converts the tangCloud directive to tang-cloud to be readable by HTML.
The tangCloud directive in tangCloud.js is where you'll find the code for that.
Edit: Just to follow up, you see the bit that says restrict: 'E'? That tells angular that you can use the directive as a custom element. When you make a directive camelcase, like tangCloud, angular will automatically convert it to tang-cloud.
.directive('tangCloud', ['$interpolate', '$compile', '$timeout', function ($interpolate, $compile, $timeout) {
var directive = {
restrict: 'E',
scope: {
width: '=',
height: '=',
words: '=',
onClick: '&',
spin: '='
},
template: function (tElement, tAttrs) {
var isClickable = angular.isDefined(tAttrs.onClick);
var clickAttr = isClickable ? 'ng-click="onClick({word : entry.word, id : entry.id})"' : '';
return "<div class='tangcloud'>" +
"<span ng-repeat='entry in words'" + clickAttr + ">{{entry.word}}</span>" +
"</div>";
},
compile: function (elem) {
elem.children().children()
.addClass('tangcloud-item-' + $interpolate.startSymbol() + 'entry.size' + $interpolate.endSymbol())
.addClass('tangcloud-item-hidden');
return function (scope, elem) {
var centerX = scope.width / 2;
var centerY = scope.height / 2;
var outOfBoundsCount = 0;
var takenSpots = [];
if (scope.words) {
scope.words = shuffleWords(scope.words);
determineWordPositions();
}
function shuffleWords(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function determineWordPositions() {
$timeout(function () {
var trendSpans = elem.children().eq(0).children();
var length = trendSpans.length;
for (var i = 0; i < length; i++) {
setWordSpanPosition(trendSpans.eq(i));
}
});
}
function setWordSpanPosition(span) {
var height = parseInt(window.getComputedStyle(span[0]).lineHeight, 10);
var width = span[0].offsetWidth;
var spot = setupDefaultSpot(width, height);
var angleMultiplier = 0;
while (spotNotUsable(spot) && outOfBoundsCount < 50) {
spot = moveSpotOnSpiral(spot, angleMultiplier);
angleMultiplier += 1;
}
if (outOfBoundsCount < 50) {
takenSpots.push(spot);
addSpanPositionStyling(span, spot.startX, spot.startY);
}
outOfBoundsCount = 0;
}
function setupDefaultSpot(width, height) {
return {
width: width,
height: height,
startX: centerX - width / 2,
startY: centerY - height / 2,
endX: centerX + width / 2,
endY: centerY + height / 2
};
}
function moveSpotOnSpiral(spot, angleMultiplier) {
var angle = angleMultiplier * 0.1;
spot.startX = centerX + (1.5 * angle) * Math.cos(angle) - (spot.width / 2);
spot.startY = centerY + angle * Math.sin(angle) - (spot.height / 2);
spot.endX = spot.startX + spot.width;
spot.endY = spot.startY + spot.height;
return spot;
}
function spotNotUsable(spot) {
var borders = {
left: centerX - scope.width / 2,
right: centerX + scope.width / 2,
bottom: centerY - scope.height / 2,
top: centerY + scope.height / 2
};
for (var i = 0; i < takenSpots.length; i++) {
if (spotOutOfBounds(spot, borders) || collisionDetected(spot, takenSpots[i])) return true;
}
return false;
}
function spotOutOfBounds(spot, borders) {
if (spot.startX < borders.left ||
spot.endX > borders.right ||
spot.startY < borders.bottom ||
spot.endY > borders.top) {
outOfBoundsCount++;
return true;
} else {
return false;
}
}
function collisionDetected(spot, takenSpot) {
if (spot.startX > takenSpot.endX || spot.endX < takenSpot.startX) {
return false;
}
return !(spot.startY > takenSpot.endY || spot.endY < takenSpot.startY);
}
function addSpanPositionStyling(span, startX, startY) {
var style = "position: absolute; left:" + startX + "px; top: " + startY + "px;";
span.attr("style", style);
span.removeClass("tangcloud-item-hidden");
}
};
}
};
return directive;
}]);
The tang-cloud directive is defined as tangCloud - take this example from the angular docs for directive
app.js
.directive('myCustomer', function() {
return {
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
index.html
<div ng-controller="Controller">
<div my-customer></div>
</div>
See the Normalization section in this part of the docs. Try searching 'tangCloud'

angularjs : how to restrict input type number to allow only even number with min and max limit as well as steps to increase

I am working on one requirement where I want to allow only even numbers to text box or number box(input type number). with minimum and maximum limit like from 4 to 14 and it should only increase by step of 2 if we have number box.
I tried with HTML input type number with min max and step attributes it's working fine but we can edit the text box with any number so to restrict I tried using directive but it's not working out for me. I will be glad if anyone can help me out with this.
HTML :
<body ng-controller="ctrl">
new : <number-only-input step="2" min="4" max="14" input-value="wks.number" input-name="wks.name" >
</body>
Script :
var app = angular.module('app', []);
app.controller('ctrl', function($scope){
$scope.name = 'Samir Shah';
$scope.price = -10;
$scope.wks = {number: '', name: 'testing'};
});
app.directive('numberOnlyInput', function () {
return {
restrict: 'EA',
template: '<input type="text" name="{{inputName}}" ng-model="inputValue" />',
scope: {
inputValue: '=',
inputName: '=',
min: '#',
max: '#',
step: '#'
},
link: function (scope) {
scope.$watch('inputValue', function(newValue,oldValue) {
var arr = String(newValue).split("");
if (arr.length === 0) return;
if (arr.length === 1 && (arr[0] == '-' || arr[0] === '.' )) return;
if (arr.length === 2 && newValue === '-.') return;
if (isNaN(newValue)) {
scope.inputValue = oldValue;
return;
}
if(!isNaN(newValue)){
if(newValue < parseInt(scope.min) || newValue > parseInt(scope.max)){
scope.inputValue = oldValue;
return;
}
}
});
}
};
});
<form name="testForm">
<div ng-controller="MyCtrl">
<input type="text" name="testInput" ng-model="number" ng-min="2" ng-max="14" required="required" numbers-only="numbers-only" />
<div ng-show="testForm.testInput.$error.nonnumeric" style="color: red;">
Numeric input only.
</div>
<div ng-show="testForm.testInput.$error.belowminimum" style="color: red;">
Number is too small.
</div>
<div ng-show="testForm.testInput.$error.abovemaximum" style="color: red;">
Number is too big.
</div>
<div ng-show="testForm.testInput.$error.odd" style="color: red;">
Numeric is odd.
</div>
</div>
</form>
angular.module('myApp', []).directive('numbersOnly', function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, modelCtrl) {
element.bind('blur', function () {
if (parseInt(element.val(), 10) < attrs.ngMin) {
modelCtrl.$setValidity('belowminimum', false);
scope.$apply(function () {
element.val('');
});
}
});
modelCtrl.$parsers.push(function (inputValue) {
// this next if is necessary for when using ng-required on your input.
// In such cases, when a letter is typed first, this parser will be called
// again, and the 2nd time, the value will be undefined
if (inputValue == undefined) return ''
var transformedInput = inputValue.replace(/[^0-9]/g, '');
if (transformedInput != inputValue || (parseInt(transformedInput, 10) < parseInt(attrs.ngMin, 10) && transformedInput !== '1') || parseInt(transformedInput, 10) > parseInt(attrs.ngMax, 10) || (transformedInput % 2 !== 0 && transformedInput !== '1')) {
if (transformedInput != inputValue) {
modelCtrl.$setValidity('nonnumeric', false);
} else {
modelCtrl.$setValidity('nonnumeric', true);
}
if (parseInt(transformedInput, 10) < parseInt(attrs.ngMin, 10) && transformedInput !== '1') {
modelCtrl.$setValidity('belowminimum', false);
} else {
modelCtrl.$setValidity('belowminimum', true);
}
if (parseInt(transformedInput, 10) > parseInt(attrs.ngMax, 10)) {
modelCtrl.$setValidity('abovemaximum', false);
} else {
modelCtrl.$setValidity('abovemaximum', true);
}
if (transformedInput % 2 !== 0 && transformedInput !== '1') {
modelCtrl.$setValidity('odd', false);
} else {
modelCtrl.$setValidity('odd', true);
}
transformedInput = '';
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
return transformedInput;
}
modelCtrl.$setValidity('nonnumeric', true);
modelCtrl.$setValidity('belowminimum', true);
modelCtrl.$setValidity('abovemaximum', true);
modelCtrl.$setValidity('odd', true);
return transformedInput;
});
}
};
});
Active fiddle http://jsfiddle.net/tuckerjt07/1Ldmkmog/
You could define a property with getter and setter to process the entered value. If the value does not match the requrements display messages but not accept new value.
Using this method you could apply any validation logic, the second field editValue is needed because otherwise you could not enter an invalid number. Therefore editValue alows to enter numbers with numerous digits which will be partially invalid during entering the value.
Property:
// Property used to bind input containing validation
Object.defineProperty($scope, "number", {
get: function() {
return $scope.editValue;
},
set: function(value) {
value = parseInt(value);
$scope.editValue = value;
var isValid = true;
// Min?
if (value < parseInt($scope.min)) {
$scope.toSmall = true;
isValid = false;
} else {
$scope.toSmall = false;
}
// Max?
if (value > parseInt($scope.max)) {
$scope.toBig = true;
isValid = false;
} else {
$scope.toBig = false;
}
// Step not valid
if (value % parseInt($scope.step) > 0) {
$scope.stepNotValid = true;
isValid = false;
} else {
$scope.stepNotValid = false;
}
$scope.isValid = isValid;
if (isValid) {
$scope.value = value;
}
}
});
Working example
Below you can find a complete working example directive containing the property described above including increase/decrease buttons:
var app = angular.module('myApp', []);
app.directive('numberOnlyInput', function() {
return {
restrict: 'E',
template: '<input type="text" ng-model="number" ng-class="{\'error\': !isValid}"/><button ng-click="increase()">+</button><button ng-click="decrease()">-</button> Value: {{value}} {{stepNotValid ? (" value must be in steps of " + step) : ""}} {{toSmall ? " value must be greater or equal to " + min : ""}} {{toBig ? " value must be smaler or equal to " + max : ""}}',
scope: {
value: '=value',
min: '#',
max: '#',
step: '#'
},
link: function($scope) {
// Increase value
$scope.increase = function() {
var newValue = parseInt($scope.value) + parseInt($scope.step);
if (newValue <= $scope.max) {
$scope.number = newValue;
$scope.editValue = $scope.number;
}
};
// Decrease value
$scope.decrease = function() {
var newValue = parseInt($scope.value) - parseInt($scope.step);
if (newValue >= $scope.min) {
$scope.number = newValue;
$scope.editValue = $scope.number;
}
};
// Property used to bind input containing validation
Object.defineProperty($scope, "number", {
get: function() {
return $scope.editValue;
},
set: function(value) {
value = parseInt(value);
$scope.editValue = value;
var isValid = true;
// Min?
if (value < parseInt($scope.min)) {
$scope.toSmall = true;
isValid = false;
} else {
$scope.toSmall = false;
}
// Max?
if (value > parseInt($scope.max)) {
$scope.toBig = true;
isValid = false;
} else {
$scope.toBig = false;
}
// Step not valid
if (value % parseInt($scope.step) > 0) {
$scope.stepNotValid = true;
isValid = false;
} else {
$scope.stepNotValid = false;
}
$scope.isValid = isValid;
if (isValid) {
$scope.value = value;
}
}
});
// Init actual Value of the input element
$scope.number = parseInt($scope.value);
$scope.editValue = parseInt($scope.value);
}
};
});
app.controller('controller', function($scope) {
$scope.value = 10;
});
.error {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="controller">
Number:
<number-only-input min="4" max="14" step="2" value="value"></number-only-input>
</div>
Why are you doing too much of work of a simple thing. Max length will not work with <input type="number" the best way I know is to use oninput event to limit the maxlength. Please see the below code, Its a generic solution work with all the Javascript framework.
<input name="somename"
oninput="javascript: if (this.value.length > this.maxLength) this.value = this.value.slice(0, this.maxLength);"
type = "number"
maxlength = "6"
/>

Trying to create D3 + AngularJS Bar Chart

I would like to create a D3 Bar chart with angularjs. This is my directive, and currently I am having a couple of problems.
The chart is not appended to the directives div, but to html tag
Chart is appended multiple times, even though when watch is called, we only log one append
When loggin d3.select(jqElm[0]), it outputs the directives element
What am I doing wrong?
(function (angular, d3) {
'use strict';
var isDef = angular.isDefined,
aExtend = angular.extend,
aCopy = angular.copy,
isArray = angular.isArray,
isObject = angular.isObject,
aElement = angular.element,
isEqual = angular.equals;
angular.module('Widgets.Module')
.factory('ConstructorD3Bar', Constructor)
.directive('tmD3Bar', Directive);
Constructor.$inject = [
'Common'
];
Directive.$inject = [
'Common',
'ConstructorD3Bar'
];
function Constructor(Common) {
var cgenerator = Common.Generator;
function D3Bar(attrs) {
this._setProps(attrs);
}
D3Bar.prototype = {
_setProps: function (p) {
p = p || {};
this.id = isDef(p.id) ? p.id : cgenerator.id;
this.theme = isDef(p.theme) ? p.theme : 'D3Bar';
this.message = isDef(p.message) ? p.message : 'D3Bar';
this.data = isDef(p.data) ? p.data : [];
this.format = isDef(p.format) ? p.format : null;
this.tsv = isDef(p.tsv) ? p.tsv : null;
this.csv = isDef(p.csv) ? p.csv : null;
this.margin = isDef(p.margin) ? p.margin : { top: 0, bottom: 0, left: 0, right: 0};
this.boxWidth = isDef(p.boxWidth) ? p.boxWidth : Common.$window.innerWidth;
this.boxHeight = isDef(p.boxHeight) ? p.boxHeight : Common.$window.innerHeight;
this.width = isDef(p.width) ? p.width : Common.$window.innerWidth;
this.height = isDef(p.height) ? p.height : Common.$window.innerHeight;
this.init();
},
init: function () {
var that = this;
if (that.tsv !== null) {
d3.tsv(that.tsv, function (err, data) {
if (isDef(err) && err && err.status) {
switch (err.status) {
case 404:
return;
}
}
that.data = data;
});
}
},
toString: function () {
return this;
}
};
return {
create: function (props) {
return new D3Bar(props);
}
};
}
function Directive(
Common,
ConstructorD3Bar
) {
var directive = {
templateUrl: 'widgets/d3-charts/bar/bar.tpl.html',
controller: ctrl,
compile: compile,
scope: {
attrs: '=?'
},
replace: true,
restrict: 'AC'
};
return directive;
function compile(tElement, tAttrs) {
return {
pre: function (scope, jqElm, attr) {
scope.initWidget = function () {
if (!isDef(scope.attrs) || scope.attrs === null) {
scope.attrs = ConstructorD3Bar.create({});
}
var margin = scope.attrs.margin,
width = scope.attrs.boxWidth - margin.left - margin.right,
height = scope.attrs.boxHeight - margin.top - margin.bottom;
scope.attrs.width = width;
scope.attrs.height = height;
var formatPercent = d3.format('.0%');
scope.attrs.x = d3.scale
.ordinal()
.rangeRoundBands([0, width], 0.1, 1);
scope.attrs.y = d3.scale
.linear()
.range([height, 0]);
scope.attrs.xAxis = d3.svg
.axis()
.scale(scope.attrs.x)
.orient('bottom');
scope.attrs.yAxis = d3.svg
.axis()
.scale(scope.attrs.y)
.orient('left')
.tickFormat(formatPercent);
};
},
post: function (scope, jqElm, attr) {
scope.$on('$destroy', function () { });
scope.$watch(
function () {
return scope.attrs.data;
},
function (nValue, oValue) {
if (!nValue) {
return;
}
if (nValue.length === 0) {
return;
}
var data = nValue;
scope.attrs.svg = d3.select(jqElm[0])
.data(data)
.enter()
.append('svg')
.attr('width', scope.attrs.width + scope.attrs.margin.left + scope.attrs.margin.right)
.attr('height', scope.attrs.height + scope.attrs.margin.top + scope.attrs.margin.bottom)
.append('g')
.attr('transform', 'translate(' + scope.attrs.margin.left + ',' + scope.attrs.margin.top + ')');
data.forEach(function (d) {
d.frequency = +d.frequency;
});
scope.attrs.x.domain(data.map(function (d) {
return d.letter;
}));
scope.attrs.y.domain([0, d3.max(data, function (d) {
return d.frequency;
})]);
scope.attrs.svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + scope.attrs.height + ')')
.call(scope.attrs.xAxis);
scope.attrs.svg.append('g')
.attr('class', 'y axis')
.call(scope.attrs.yAxis)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Frequency');
scope.attrs.svg.selectAll('.bar')
.data(data)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', function (d) {
return scope.attrs.x(d.letter);
})
.attr('width', scope.attrs.x.rangeBand())
.attr('y', function (d) {
return scope.attrs.y(d.frequency);
})
.attr('height', function (d) {
return scope.attrs.height - scope.attrs.y(d.frequency);
});
}
);
}
};
}
function ctrl($scope, $element, $attrs) {
var vm = $scope;
if (!isDef(vm.attrs) || vm.attrs === null) {
vm.attrs = ConstructorD3Bar.create({ });
}
var attrs = vm.attrs;
}
}
})(window.angular, window.d3);
<div id="{{ attrs.id }}" class="D3Bar" ng-class="attrs.theme" ng-init="initWidget()">
</div>
Remove .data().enter in .select
scope.attrs.svg = d3.select(jqElm[0])
.append('svg')
.attr('width', scope.attrs.width + scope.attrs.margin.left + scope.attrs.margin.right)
.attr('height', scope.attrs.height + scope.attrs.margin.top + scope.attrs.margin.bottom)
.append('g')
.attr('transform', 'translate(' + scope.attrs.margin.left + ',' + scope.attrs.margin.top + ')');

Converting CSS Sticky Plugin Into Angular Directive

I am trying to use this Sticky CSS plugin with an Angular Directive. I tried wrapping this code into a Directive but no luck yet getting it to work.
Here is the CodePen of the plugin without Angular - http://codepen.io/chrissp26/pen/gBrdo
and this is what I have so far.
Any help or guidance would be greatly appreciated.
app.directive('sticky', function() {
return function stickyTitles(stickies) {
this.load = function() {
stickies.each(function(){
var thisSticky = jQuery(this).wrap('<div class="followWrap" />');
thisSticky.parent().height(thisSticky.outerHeight());
jQuery.data(thisSticky[0], 'pos', thisSticky.offset().top);
});
}
this.scroll = function() {
stickies.each(function(i){
var thisSticky = jQuery(this),
nextSticky = stickies.eq(i+1),
prevSticky = stickies.eq(i-1),
pos = jQuery.data(thisSticky[0], 'pos');
if (pos <= jQuery(window).scrollTop()) {
thisSticky.addClass("fixed");
if (nextSticky.length > 0 && thisSticky.offset().top >= jQuery.data(nextSticky[0], 'pos') - thisSticky.outerHeight()) {
thisSticky.addClass("absolute").css("top", jQuery.data(nextSticky[0], 'pos') - thisSticky.outerHeight());
}
} else {
thisSticky.removeClass("fixed");
if (prevSticky.length > 0 && jQuery(window).scrollTop() <= jQuery.data(thisSticky[0], 'pos') - prevSticky.outerHeight()) {
prevSticky.removeClass("absolute").removeAttr("style");
}
}
});
}
}
return function(){
var newStickies = new stickyTitles(jQuery(".followMeBar"));
newStickies.load();
jQuery(window).on("scroll", function() {
newStickies.scroll();
});
};
});
try this:
<sticky>
<div class="followMeBar">a</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">b</div>
</sticky>
directive:
app.directive('sticky', function() {
var stickyTitles = function (stickies) {
this.load = function() {
stickies.each(function() {
var thisSticky = jQuery(this).wrap('<div class="followWrap" />');
thisSticky.parent().height(thisSticky.outerHeight());
jQuery.data(thisSticky[0], 'pos', thisSticky.offset().top);
});
}
this.scroll = function() {
stickies.each(function(i) {
var thisSticky = jQuery(this),
nextSticky = stickies.eq(i + 1),
prevSticky = stickies.eq(i - 1),
pos = jQuery.data(thisSticky[0], 'pos');
if (pos <= jQuery(window).scrollTop()) {
thisSticky.addClass("fixed");
if (nextSticky.length > 0 && thisSticky.offset().top >= jQuery.data(nextSticky[0], 'pos') - thisSticky.outerHeight()) {
thisSticky.addClass("absolute").css("top", jQuery.data(nextSticky[0], 'pos') - thisSticky.outerHeight());
}
} else {
thisSticky.removeClass("fixed");
if (prevSticky.length > 0 && jQuery(window).scrollTop() <= jQuery.data(thisSticky[0], 'pos') - prevSticky.outerHeight()) {
prevSticky.removeClass("absolute").removeAttr("style");
}
}
});
}
}
return {
restrict: 'E',
link: function(scope, element, attrs) {
var newStickies = new stickyTitles($(element).find(".followMeBar"));
newStickies.load();
jQuery(window).on("scroll", function() {
newStickies.scroll();
});
}
};
http://plnkr.co/edit/13w5e7n0ReWoaO8513K5?p=preview

Resources