I try to open a modal view. For that i use the following:
crop: function(options) {
options = this.initOptions(options);
var scope = $rootScope.$new(true);
ionic.extend(scope, options);
scope.modal = $ionicModal.fromTemplate(template, {
scope: scope
});
// Show modal and initialize cropper.
return scope.modal.show().then(function() {
return (new jrCropController(scope)).promise.promise;
});
},
This is working fine. But now i dont want to define my template inside the javascript. I want to define my template in an extra html file and so i did.
So i had to replace this:
$ionicModal.fromTemplate(template,
with this:
$ionicModal.fromTemplateUrl(url,
But now i get the following error:
ionic.bundle.js:20306 TypeError: scope.modal.show is not a function
at Object.crop (jr-crop.js:287)
at Scope.$scope.crop (polaroids_edit.js:51)
at $parseFunctionCall (ionic.bundle.js:21044)
at ionic.bundle.js:53458
at Scope.$eval (ionic.bundle.js:23100)
at Scope.$apply (ionic.bundle.js:23199)
at HTMLButtonElement.<anonymous> (ionic.bundle.js:53457)
at HTMLButtonElement.eventHandler (ionic.bundle.js:11713)
at triggerMouseEvent (ionic.bundle.js:2863)
at tapClick (ionic.bundle.js:2852)
Why do i get this error when i use a template url instead of a template? For me that makes no sense since it is the same method in both cases.
I think that you're missing the fact that the fromTemplate() returns the modal object while fromTemplateUrl() returns a promise, since you're loading the template asynchronously.
Thus, this works fine
scope.modal = $ionicModal.fromTemplate(template, {
scope: scope
});
while this will not work
scope.modal = $ionicModal.fromTemplateUrl(url, {
scope: scope
});
since scope.modal will be a promise object.
You will have to wait for the promise to resolve and then assign the modal, like
$ionicModal.fromTemplateUrl(url, {
scope: $scope,
}).then(function(modal) {
$scope.modal = modal;
});
For reference check out $ionicModal: fromTemplate vs. fromTemplateUrl functions
crop: function(options) {
options = this.initOptions(options);
var scope = $rootScope.$new(true);
ionic.extend(scope, options);
$ionicModal.fromTemplateUrl(template, {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
scope.modal = modal;
return scope.modal.show().then(function() {
return (new jrCropController(scope)).promise.promise;
});
});
}
Iconic modal
Related
I'm trying to inject $q into my directive, but though $q is defined as a resolver() at first, when calling the function it is undefined. Maybe something related to binding? I don't know.
(function () {
'use strict';
myForm.$inject = ["$q"];
angular
.module('myModule')
.directive('myForm', myForm);
function myForm($q) {
return {
restrict: 'EA',
scope: {
ngSubmitFunction: '&',
},
templateUrl: 'myTemplate',
controllerAs: 'ctrl',
controller: ["$scope", "$window", "$q", function ($scope, $window, $q) {
var vm = this;
vm.name = 'myForm';
$scope.submitPromise = function(){};
vm.ngSubmit = ngSubmit;
function ngSubmit($form) {
vm.submitDisabled = true;
$form.$setSubmitted();
if ($form.$valid) {
$scope.submitPromise().then(function() {
vm.submitDisabled = false;
});
}
}
}],
link: function (scope, element, attrs) {
console.log($q);
scope.submitPromise = function($q) {
console.log($q);
var deferred = $q.defer();
scope.ngSubmitFunction();
return deferred.promise;
}
}
};
}
}());
The objective is to call ngSubmit when user clicks on a button. ngSubmit disables the button, waits for the async calls to be over and then enables the button.
In the example code, the 1st console.log($q) (executed when loading the page) outputs this:
Q(resolver) {
if (!isFunction(resolver)) {
throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
}...
Which to me looks like correct.
But when calling submitPromise() after pressing the button, this is the output:
undefined
TypeError: Cannot read property 'defer' of undefined
When is $q lost?
Note: this is not the only version I tried, originally all code was on controller, nothing on link. I've also been told this pattern is deprecated and to use this one, which is better:
function submitPromise($q) {
return $q(function (resolve) {
$scope.ngSubmitFunction();
})
}
Nothing worked. Everything produces the same error, $q gets undefined at some point and can't find out why.
Using $q as an argument parameter is causing $q to become undefined.
myForm.$inject = ["$q"];
angular
.module('myModule')
.directive('myForm', myForm);
function myForm($q) {
return {
link: function (scope, element, attrs) {
console.log($q);
//scope.submitPromise = function($q) {
//Remove $q as parameter
scope.submitPromise = function() {
console.log($q);
var deferred = $q.defer();
//scope.ngSubmitFunction();
deffered.resolve(scope.ngSubmitFunction());
return deferred.promise;
}
}
The myForm function is a directive construction function to which the AngularJS framework will inject service providers. But the submitPromise function is not injectable; it is a child function of myForm. All injections should be done in the parent function.
Also the code can be simplified by using $q.when to create a promise.
link: function (scope, element, attrs) {
console.log($q);
//scope.submitPromise = function($q) {
//Remove $q as parameter
scope.submitPromise = function() {
console.log($q);
return $q.when(scope.ngSubmitFunction());
}
}
You should solve with this different injection
(function () {
'use strict';
angular
.module('myModule')
.directive('myForm', ['$q', function($q){
return {
. . .
}
}]);
Hope I've been helpful.
The right code is ( I removed parameter from function declaration ):
$scope.submitPromise=function() {
return $q(function (resolve) {//$q is available in function declared in the same scope
$scope.ngSubmitFunction();
});
}
Above code use $q variable from scope ( javascript scope not angular $scope ), $q is visible for all functions declared inside myForm function.
Your previous code used function parameter not $q from scope, parameter was not passed, so was undefined.
Javascript scope means everything between open tag { and close tag }. Check this example:
function(y){//scope start
var x; //scope local variable
var someFunc=function(){
//here is available y and x variables
};
//scope end
}
//outside of scope - here variables x and y not exists
I have a slideshow directive (self-made) which is adjustable - some variables change, for instance, I have a scope variable containing these settings:
{
animationSpeed : 30,
transitionTime : 1.5
}
As animation library I use greensock (GSAP) and the animations are defined as follows :
ModuleSlideshow.animation('.slide-left-animation', ['$window',function ($window) {
"use strict";
var getScope = function(e){
var scope = angular.element(e).scope();
if(scope){ scope = scope.$parent; }
if(scope){ scope = scope.$parent; }
return scope;
};
return {
enter: function (element, done) {
TweenMax.fromTo(element, getScope(element).animationSpeed, {left: -$window.innerWidth, ease : Power4.easeInOut}, {left: 0, ease: Power4.easeInOut, onComplete: done});
},
leave: function (element, done) {
TweenMax.to(element,getScope(element).animationSpeed,{left : $window.innerWidth,ease : Power4.easeInOut, onComplete: done});
}
};
}]);
As you can see there I try to grab the scope with the element I get (the element is a .slide div, and I go up to the parent twice (to grab correct variables).
This works sometimes, but sometimes not, and I get some JavaScript error saying that "cannot read property $parent of null". I tried to inject $scope directly, but this doesn't seem to work. How would you access scope in my case? Should I change the way I setup the animation?
I ran into a problem almost exactly like yours where I needed to access the element's scope. It seemed using element.scope() will be fine but will break especially if you intend to use $compileProvider.debugInfoEnabled(false);, which is recommended in Angular apps for performance. Although you lose access to the scope of the element when you turn off Debug Info, you still do have access to the element's controller via data().
Perhaps if you refactor your code to utilize a controller for your directive, you'll be able to access the scope variable you need.
angular.module('myApp')
.config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}])
.controller('myDirectiveCtrl', function ($scope, $el) {
this.animationSpeed = $scope.animationSpeed;
})
.directive('myDirective', function () {
return {
restrict: 'E',
scope: {
animationSpeed: '='
},
controller: 'myDirectiveCtrl',
controllerAs: 'vm'
};
})
.animation('.my-directive', function () {
return {
addClass: function (element, className, done) {
var vm = element.data().$myDirectiveController;
console.log(vm.animationSpeed, className);
},
removeClass: function (element, className, done) {
var vm = element.data().$myDirectiveController;
console.log(vm.animationSpeed, className);
}
}
})
I tried the one above; I could not inject scope into the directive controller. I created a service instead to communicate like so and it works well and I can keep the them ..
angular
.module('App')
.service('SliderService', function (){
return {
direction: null
};
});
angular
.module("App")
.directive('slider',slider);
slider.$inject = ['SliderService'];
link: function (scope, elem, attrs) { var unbindWatch = scope.$watch('direction', function () { SliderService.direction = scope.direction });
Remember to kill watches and timers with scope.
scope.$on('destroy',function () { unbindWatch() }) }
Then for the animation use the following
angular
.module("App")
.animation('.slide-animation', slideAnimation);
slideAnimation.$inject =['SliderService'];
function slideAnimation ( SliderService) {
return {
beforeAddClass: function (element, className, done) {
if (className == 'ng-hide' && SliderService.direction) { ... }
}
}
I have a parent controller where I set instantiate an object called links. I assign a property with a value that I want to change within another function. However when I set the variable in the instagramModel the links.imagesa doesn't get updated.
I print the value out in the console and the parentscope doesn't get updated. I have thought I followed the rules of prototypical inheritance.
Why is $scope.links.imagesa not updating?
.controller('HomeCtrl', function HomeController($scope, titleService, config, $sails, $timeout, $upload, leafletData, $modal, $log) {
$scope.links = {};
$scope.links.imagesa = "This should change";
$scope.instagramModal = function (size) {
var modalInstance = $modal.open({
templateUrl: 'instagramModal.html',
controller: 'InstagramModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $sails.get("/instagram/self").success(function (response) {
return response.data;
}).error(function (response) {
console.log('error');
});
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.links.imagesa = "wept";
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$scope.ask = function () {
console.log($scope.links.imagesa);
};
});
If you want the parent's scope to get updated, then you must use $scope.$parent.links.imagesa since the changes made in child scope are not reflected in the parent scope directly.
I had the HomeCtrl instantiated in the UI Router and also on the template page using ng-controller. This messed up the scope.
Angular UI's modals use $rootScope by default. See documentation at "http://angular-ui.github.io/bootstrap/#/modal"
You can pass a scope parameter with a custom scope when you open the modal – e.g. scope: $scope if you want to pass the parent scope. The modal controller will create a sub-scope from that scope, so you will only be able to use it for your initial values.
Hence, if you want to update any value, keep the object/data in rootScope.
I'm using (the awesome) Restangular and i'm running into something that forces me to use scope.$parent (not awesome), and i don't want to use that. It seems even though my controller is the parent scope to my directive's scope, the = isolated scope binding is evaluated before my parent controller is executed.
With the following HTML:
<div ng-controller="myController">
<div x-my-directive x-some-value="parentValue"></div>
</div>
And the following directive:
myApp.directive("myDirective", function () {
return {
restrict: 'A',
link: function (scope, elem) {
console.log(scope.someValue); // Logs 'undefined' :(
},
scope: {
someValue: "="
}
}
});
And the following controller:
myApp.controller("myController", function($scope, allMyValues) {
allMyValues.getList().then(function(parentValue){
$scope.parentValue = parentValue;
});
}
As shown in my directives link function, evaluating a scope property that should have been bound to my parent's scope property returns undefined. However when i change my directives link function to the following:
myApp.directive("myDirective", function () {
return {
restrict: 'A',
link: function (scope, elem) {
setTimeout(function() {
console.log(scope.someValue); // Logs '{1: number_1, 2: number_2}'
}, 2000);
},
scope: {
someValue: "="
}
}
});
How do i go about resolving this??
Thanks
that should helps:
myApp.controller("myController", function($scope, allMyValues) {
//add this line
$scope.parentValue={};
allMyValues.getList().then(function(parentValue){
$scope.parentValue = parentValue;
});
}
$scope.parentValue not exist until your request is resolved so add line like below to your code
sample demo http://jsbin.com/komikitado/1/edit
Looks like you are waiting for a promise to resolve before assigning the value to the scope.
There are a few ways you might handle this.
One way is to try moving the Restangular call to a resolve function for the view which holds the controller. Then you get access to the resolved data directly as an injection in your controllers
Another way might be to just assign the promise directly to the scope and then in the linking function wait for a resolution.
scope.someValue.then(function(value) { console.log(value); });
I want to capture the url of my query in an AngularJS service as this
var mortgageloanService = angular.module('loanstreetIpadAppApp', []);
mortgageloanService.factory('updateTable', function($http) {
return {
getParams: function() {
var url = 'https://api.mongolab.com/api/1/databases/angularjs-intro/collections/users?apiKey=terrPcifZzn01_ImGsFOIZ96SwvSXgN9';
console.log('in service mode');
console.log(url);
return $http.get(url);
}
};
});
This is my controller.js code
angular.module('loanstreetIpadAppApp')
.controller('Mortgage_LoanCtrl', function ($location, $scope) {
$scope.update_result = function(updateTable) {
updateTable.getParams().success(function(loan){$scope.loan = loan});
console.log($scope.resulttable);
};
});
On my view page, i have a button which onclick shud call the update_result function. But whenever i click on the button i get the following error
TypeError: Cannot read property 'getParams' of undefined
at Scope.$scope.update_result (http://localhost:9003/scripts/controllers/mortgage_loan.js:22:16)
at http://localhost:9003/bower_components/angular/angular.js:10567:21
at http://localhost:9003/bower_components/angular/angular.js:18627:17
at Scope.$eval (http://localhost:9003/bower_components/angular/angular.js:12412:28)
at Scope.$apply (http://localhost:9003/bower_components/angular/angular.js:12510:23)
at HTMLButtonElement.<anonymous> (http://localhost:9003/bower_components/angular/angular.js:18626:21)
at HTMLButtonElement.jQuery.event.dispatch (http://localhost:9003/bower_components/jquery/dist/jquery.js:4430:9)
at HTMLButtonElement.elemData.handle (http://localhost:9003/bower_components/jquery/dist/jquery.js:4116:28)
Anyone knows how to solve this issue?
In order to use your updateTable's factory inside your controller, you need to inject it. So, your controller should look like this.
angular.module('loanstreetIpadAppApp')
.controller('Mortgage_LoanCtrl', function ($location, $scope, updateTable) {
$scope.update_result = function() {
updateTable.getParams().success(function(loan){$scope.loan = loan});
console.log($scope.resulttable);
};
});
Notice that I've removed "updateTable" as "$scope.update_result"'s parameter since it would overwrite your updateTable object inside that closure.