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

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

Related

Mapbox & Angular Iframe doens't work on Firefox

I have deployed Angular to my Codigniter project and also I have deployed MapBox Leaflet to it as part of my project, but it doesn't work on Firefox, what I have done I used the scope and angular object inside the iFrame I use to load the mapbox map view. It works seamlessly on other browsers, but it doesn't work on Firefox.
This is the error I get on my Console
WARNING: Tried to load angular more than once.
angular.min.js (line 206)
TypeError: a is null
<iframe width="100%" height="600px" src="URL/ADDRESS/TO/MAP/WHERE/I/REUSE/ANGULAR/AND/SCOPE/AGAIN" frameborder="0"></iframe>
<!DOCTYPE html>
https://api.mapbox.com/mapbox.js/v2.2.4/mapbox.js'>
https://api.mapbox.com/mapbox.js/v2.2.4/mapbox.css' rel='stylesheet' />
" type="text/javascript">
https://api.mapbox.com/mapbox.js/plugins/mapbox-directions.js/v0.4.0/mapbox.directions.css' type='text/css' />
" />
</head>
<body class="plugin-mapbox-driving-direction-mapview">
<section class="">
<div class="">
<div id='map'></div>
<div id='inputs'></div>
<div id='errors'></div>
<div id='directions'><div id='routes'></div><div id='instructions'></div></div>
<script>
var angular = window.parent.angular,
scope = window.parent.angular.element(window.frameElement).scope(),
initialization = true;
//console.log("angular", angular, "angular");
//console.log("scope", scope, "scope");
var startCoordinates = scope.__route[0],
endCoordinates = scope.__route[1];
var startLocation = {
lat: angular.isDefined(startCoordinates.lat) ? startCoordinates.lat : null,
lng: angular.isDefined(startCoordinates.lng) ? startCoordinates.lng : null,
loc: scope.pinOriginLocation
},
endLocation = {
lat: angular.isDefined(endCoordinates.lat) ? endCoordinates.lat : null,
lng: angular.isDefined(endCoordinates.lng) ? endCoordinates.lng : null,
loc: scope.pinDestinationLocation
},
origin = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [startLocation.lng, startLocation.lat]
},
properties: {
name: startLocation.loc
}
},
destination = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [endLocation.lng, endLocation.lat]
},
properties: {
name: endLocation.loc
}
};
L.mapbox.accessToken = "<?php echo $this->config->item('mapbox_api_accesstoken'); ?>";
var __journey = scope.__journey;
var map = L.mapbox.map('map', 'mapbox.streets', {zoomControl: false});
map.attributionControl.setPosition('bottomleft');
var directions = L.mapbox.directions();
var directionsLayer = L.mapbox.directions.layer(directions).addTo(map);
var directionsRoutesControl = L.mapbox.directions.routesControl('routes', directions).addTo(map);
var directionsInputControl = L.mapbox.directions.inputControl('inputs', directions).addTo(map);
var directionsErrorsControl = L.mapbox.directions.errorsControl('errors', directions).addTo(map);
var directionsInstructionsControl = L.mapbox.directions.instructionsControl('instructions', directions).addTo(map);
var wayPoints = [];
if(angular.isDefined(scope.__journey.__route) && scope.__journey.__route.length > 2) {
for(var i in scope.__journey.__route) {
if(scope.__journey.__route.length <= 20 || (wayPoints.length <= 20 && Number(i)%(Math.round(scope.__journey.__route.length / 20)) == 0))
wayPoints.push(L.latLng(scope.__journey.__route[i].latitude,scope.__journey.__route[i].longitude));
}
}
console.log("wayPoints", wayPoints, "wayPoints");
setQuery(startLocation, true, origin, endLocation, true, destination, wayPoints);
//directions.setOrigin(origin, true).setDestination(destination, true).query(undefined, false);
scope.$watch("pinOriginLocation", function(newval, oldval) {
if(angular.isDefined(newval) && newval.length >= 20 && newval !== oldval) {
startCoordinates = scope.getCordinates(newval);
startLocation = {
lat: angular.isDefined(startCoordinates.lat) ? startCoordinates.lat : null,
lng: angular.isDefined(startCoordinates.lng) ? startCoordinates.lng : null,
loc: scope.pinOriginLocation
};
origin = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [startLocation.lng, startLocation.lat]
},
properties: {
name: startLocation.loc
}
};
initialization = false;
setQuery(startLocation, undefined, origin, endLocation, undefined, destination, wayPoints);
//directions.setOrigin(origin).setDestination(destination).query(undefined, false);
}
});
scope.$watch("pinDestinationLocation", function(newval, oldval) {
if(angular.isDefined(newval) && newval.length >= 20 && newval !== oldval) {
endCoordinates = scope.getCordinates(newval);
endLocation = {
lat: angular.isDefined(endCoordinates.lat) ? endCoordinates.lat : null,
lng: angular.isDefined(endCoordinates.lng) ? endCoordinates.lng : null,
loc: scope.pinDestinationLocation
};
destination = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [endLocation.lng, endLocation.lat]
},
properties: {
name: endLocation.loc
}
};
initialization = false;
setQuery(startLocation, undefined, origin, endLocation, undefined, destination, wayPoints);
//directions.setOrigin(origin).setDestination(destination).query(undefined, false);
}
});
function suggestLocation(event, element) {
var el = $(element);
if(el.val().length >= 8 && event.keyCode == 32) {
$.ajax({
type : "POST",
url : siteVars.ajaxUrl+"webservice/lookupAddress",
datatype : "html",
data : {
"code" : siteVars.csrfHash,
"address" : el.val()
},
success: function(data) {
lookup = [];
if(!angular.equals(data, "")) {
data = JSON.parse(data);
for(var i in data) {
if(typeof data[i].location != 'undefined')
lookup.push(data[i].location);
}
displaySuggestion(el, lookup);
}
}
});
}
};
function displaySuggestion(element, lookup) {
var attr = element.attr("id") + "DataList";
var html = "";
$("#"+attr).remove();
if(lookup.length > 0) {
for(var i in lookup)
html += "<div onclick='selectSuggestion(\""+element.attr("id")+"\", \""+lookup[i]+"\")' class='autocomplete-suggestion' data-index='"+i+"'>"+lookup[i]+"</div>";
html = "<div class='autocomplete-suggestions' id='"+attr+"'>"+html+"</div>";
$(html).insertAfter(element);
}
};
function selectSuggestion(element, suggestion) {
var el = $("#"+element);
el.val(suggestion);
$("#"+el.attr("id")+"DataList").remove();
if(el.attr("id") == "mapbox-directions-origin-input")
directions.setOrigin(suggestion);
if(el.attr("id") == "mapbox-directions-destination-input")
directions.setDestination(suggestion);
if(directions.queryable()) {
initialization = false;
directions.query({proximity: map.getCenter()}, false);
}
}
function setQuery(startLocation, startLocationStatus, origin, endLocation, endLocationStatus, destination, wayPoints) {
if(!angular.isDefined(startLocation.loc) || angular.equals(startLocation.loc, "") || angular.equals(startLocation.loc, null))
directions.setOrigin(L.latLng(startLocation.lat, startLocation.lng), true);
else
directions.setOrigin(origin, true);
if(!angular.isDefined(endLocation.loc) || angular.equals(endLocation.loc, "") || angular.equals(endLocation.loc, null))
directions.setDestination(L.latLng(endLocation.lat, endLocation.lng), true);
else
directions.setDestination(destination, true);
if(angular.isDefined(wayPoints) && wayPoints.length > 0)
directions.setWaypoints(wayPoints);
//L.Routing.control({waypoints:wayPoints}).addTo(map);
console.log("wayPoints", wayPoints, "wayPoints");
return directions.query(undefined, false);
}
</script>
</div>
<?=$this->load->view("subviews/libraries_link")?>
</section>
</body>

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 + ')');

Is there a extJS tri state/three state checkbox?

Looking for a checkbox that can hold three states.
Use:
True, False, Unknown.
Expected behavior:
[x], [ ], [~]
Anyone know of anything?
Ext 3.* Tri-state from this website
Ext 6.2.1
This code exerpt is from sencha forums
{
name: 'optionalChange',
fieldLabel: 'Optional change',
xtype: 'tri-checkbox',
value: 'null'
},
.x-checkbox-null .x-form-checkbox-default {
border: 1px inset #a0a0a0;
background: lightgrey;
box-shadow: 0 0 0 1px hsl(0, 0%, 80%);
}
/**
* Tri-state Checkbox.
* Author: ontho & nux
* Source: https://www.sencha.com/forum/showthread.php?138664-Ext.ux.form.TriCheckbox&p=619810
*
* Note! You must add `x-checkbox-null` style for yourself.
* This might work for classic theme:
.x-checkbox-null .x-form-checkbox-default {
background-position: -39px -26px;
}
*
*/
Ext.define('Ext.ux.form.TriCheckbox', {
extend: 'Ext.form.field.Checkbox',
alias: ['widget.xtricheckbox', "widget.tri-checkbox"],
triState: true, // triState can dynamically be disabled using enableTriState
values: ['null', '0', '1'], // The values which are toggled through
checkedClasses: ['x-checkbox-null', '', Ext.baseCSSPrefix + 'form-cb-checked'], // The classes used for the different states
currentCheck: 0, // internal use: which state we are in?
getSubmitValue: function()
{
return this.value;
},
getRawValue: function()
{
return this.value;
},
getValue: function()
{
return this.value;
},
initValue: function()
{
var me = this;
me.originalValue = me.lastValue = me.value;
me.suspendCheckChange++;
me.setValue(me.value);
me.suspendCheckChange--;
},
setRawValue: function(v)
{
var me = this;
if (v === false || v == 0)
v = '0';
if (v === true || v == 1)
v = '1';
if (v == null || v == '' || v === undefined)
{
if (!this.triState)
v = '0';
else
v = 'null';
}
var oldCheck = me.currentCheck;
me.currentCheck = me.getCheckIndex(v);
me.value = me.rawValue = me.values[me.currentCheck];
// Update classes
var inputEl = me.inputEl;
if (inputEl)
{
inputEl.dom.setAttribute('aria-checked', me.value == '1' ? true : false);
}
me['removeCls'](me.checkedClasses)
me['addCls'](me.checkedClasses[this.currentCheck]);
},
// this is a defaul Checkbox style setter we need to override to remove defult behaviour
updateCheckedCls: function(checked) {
},
// Returns the index from a value to a member of me.values
getCheckIndex: function(value)
{
for (var i = 0; i < this.values.length; i++)
{
if (value === this.values[i])
{
return i;
}
}
return 0;
},
// Handels a click on the checkbox
listeners: {
afterrender: function()
{
var me = this;
this.el.dom.onclick = function(){
me.toggle();
return false;
};
}
},
// Switches to the next checkbox-state
toggle: function()
{
var me = this;
if (!me.disabled && !me.readOnly)
{
var check = me.currentCheck;
check++;
if (check >= me.values.length) {
check = (me.triState == false) ? 1 : 0;
}
this.setValue(me.values[check]);
}
},
// Enables/Disables tristate-handling at runtime (enableTriState(false) gives a 'normal' checkbox)
enableTriState: function(bTriState)
{
if (bTriState == undefined)
bTriState = true;
this.triState = bTriState;
if (!this.triState)
{
this.setValue(this.value);
}
},
// Toggles tristate-handling ar runtime
toggleTriState: function()
{
this.enableTriState(!this.triState);
}
});

directive function calling multiple times in 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 ?

Resources