$ionicModal can't update $scope? - ionic-framework

I have trouble with updating a $scope object when It's inside a Modal.
$scope.lists = {};
$ionicModal.fromTemplateUrl('foobar-show.html', function($ionicModal) {
$scope.modal = $ionicModal;
}, {
scope: $scope
});
As you can see it's the normal $ionicModal
And it opens the Modal with this: <a ng-click="doOpen()">Modal</a>
$scope.doOpen = function(){
$scope.modal.show();
$scope.foobar = {};
};
Inside I do a {{ lists.length }} > returns 0
But then I'm calling inside that Modal the function:
$scope.fooAction = function(a){
$scope.lists.push(a);
alert($scope.lists.length);
};
The alert returns a +1. So 1 after the first time, but the View of the modal still returns 0... Is it a different scope or something? I pass it with the ionicModal, right? How to fix this?

Beacause the modal is created the first you enter the view and than is being cached, you have to tell your view not to cache it.
<ion-view cache-view="false">

Related

What is the need of $scope.closeModal?

Here is my code..If I remove close modal function,there is no effect. If I click any where outside the modal, the modal closes. But I need this close modal function as I need to set a flag in it for further use. How can I proceed further?
$scope.$on('$ionicView.afterEnter', function() {
$scope.openModal();
}
$ionicModal.fromTemplateUrl("settings/settingsModal.html", {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
});
$scope.openModal = function(){
$scope.modal.show();
}
$scope.closeModal = function(){
$scope.modal.hide();
};
}
There are a two ways of implementing modal in Ionic. One way is to add separate template and the other is to add it on top of the regular HTML file, inside script tags. First thing we need to do is to connect our modal to our controller using angular dependency injection. Then we need to create modal. We will pass in scope and add animation to our modal.
After that we are creating functions for opening, closing, destroying modal and the last two functions are place where we can write code that will be triggered if modal is hidden or removed. If you don't want to trigger any functionality when modal is removed or hidden you can delete the last two functions.
Controller's Code:
.controller('MyController', function($scope, $ionicModal) {
$ionicModal.fromTemplateUrl('my-modal.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
});
$scope.openModal = function() {
$scope.modal.show();
};
$scope.closeModal = function() {
$scope.modal.hide();
};
//Cleanup the modal when we're done with it!
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
// Execute action on hide modal
$scope.$on('modal.hidden', function() {
// Execute action
});
// Execute action on remove modal
$scope.$on('modal.removed', function() {
// Execute action
});
});
HTML Code :
<script id = "my-modal.html" type = "text/ng-template">
<ion-modal-view>
<ion-header-bar>
<h1 class = "title">Modal Title</h1>
</ion-header-bar>
<ion-content>
<button class = "button icon icon-left ion-ios-close-outline"
ng-click = "closeModal()">Close Modal</button>
</ion-content>
</ion-modal-view>
</script>
There are also other options for modal optimization. I already showed how to use scope and animation. The table below shows other options.
Modal options
The close modal function is meant for situations where you would like to close the modal manually. For example after a certain time it has been open or if something happens/the user does something for example presses a button.
There are ways of listening to when the modal is hidden/removed which will suit your situation and needs. For example:
// Execute action on hide modal
$scope.$on('modal.hidden', function() {
// Execute action
console.log('modal was hidden');
});
// Execute action on remove modal
$scope.$on('modal.removed', function() {
// Execute action
console.log('modal was removed');
});
With these you should be able to do what I understood you are wanting to do.
Straight from the documentation: http://ionicframework.com/docs/api/service/$ionicModal/

Ionicmodal Doesn't Open Until Third Click/Tap

I have set the on-tap value of a div to open a modal which is defined in the page's controller. The div is part of an ng-repeat section. The modal function also accepts some variables passed to it by the div.
When the app is first started on my device (iPhone 6 running iOS 7), I have to tap the div three times before the modal will open. After that, it opens consistently when I tap. But when the app first starts, I have to tap the div 3 times.
There are no errors at all in the console. Once the modal does open, it works as expected.
Any advice?
Here's the code:
HTML
<div on-tap="doModal('{{embed.ID}}','reply','{{embed.oembed}}','{{embed.user}}');">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75 72" width="100" height="50">
<path d="imagestuffhere"/>
</svg>
</div>
CONTROLLER
$scope.doModal = function(this_ID,modaltype,this_oembed,this_user) {
$scope.contact = {
name: this_ID,
info: modaltype,
oembed: this_oembed,
user: this_user
}
if (modaltype == 'repost') {
$scope.modaltempl = 'templates/repost-modal.html';
}
else if (modaltype == 'reply') {
$scope.modaltempl = 'templates/reply-modal.html';
}
else if (modaltype == 'like') {
$scope.modaltempl = 'templates/like-modal.html';
}
else {
$scope.modaltempl = 'templates/like-modal.html';
}
$ionicModal.fromTemplateUrl($scope.modaltempl, {
scope: $scope,
animation: 'slide-in-up'
}).then(function (modal) {
$scope.modal = modal;
$scope.modal.show();
console.log($scope.modaltempl);
});
};
$scope.closeModal = function() {
$scope.modal.hide();
};
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
I've tried pulling the $ionicModal.fromTemplateUrl($scope.modaltempl, bit outside of $scope.doModal and calling $scope.modal.show from within $scope.doModal, but the result is the same.
It definitely gets to the scope.modal.show(); statement even when the modal does not open, because the console.log I've included just after it gets output.
Before I had added the svg to the interface, I was testing this using a button element and had the same issue. It also had the same issue when I used ng-click instead of on-tap.
Thanks for any help!
Turns out the issue was not in the Ionic controller code nor the triggering html, but in the modal template, itself.
Per the Ionic documentation, I had each of my modal templates wrapped in this:
<script type="text/ng-template" id="repost-modal.html"></script>
By removing that and replacing it with just <ion-modal-view></ion-modal-view> the issue was resolved and the modals now open very nicely on the first click.

Problems using $ionicLoading and modal view

Something strange is happening to my app. I'm using $ionicLoading to show and hide the loading template when I go to a page of my app. Everything works fine in the current page after the loading template appears, but if I open a modal page in the current view, it'll be showed but I won't be able to interact with the modal view, everything seems frozen. The app continues running but I can't select anything in the modal. I'm pretty sure that $ionicLoading is what is making this problem appears because if I eliminate it, everything works fine.
So, How could I solve it?.
.controller('AppCtrl', function($scope, $ionicModal, $timeout, $http, $ionicPopover, $rootScope,$ionicLoading) {
$ionicModal.fromTemplateUrl('templates/nuevoEvento.html', {
scope: $scope,
animation: 'slide-in-right'
}).then(function(modal) {
$scope.modalEvento = modal;
});
// Open the login modal
$scope.evento = function() {
$scope.modalEvento.show();
};
$scope.closeEvento = function() {
$scope.modalEvento.hide();
};
$scope.showLoading = function() {
$ionicLoading.show({
template: 'Loading...'
});
};
$scope.hideLoading = function(){
$ionicLoading.hide();
};
})
.controller('EventosCtrl', function($scope, $stateParams, $http, $timeout,$ionicLoading ) {
$scope.init=function(){
$scope.showLoading();
$http({method: 'GET', url: BASEPATH + '/eventos'})
.success(function(data){
$scope.hideLoading();
$scope.eventos = data;
console.log(data);
var evLeft = [];
var evRight = [];
for(var i = 0; i < data.length; i = i + 2){
evLeft.push(data[i]);
if(data[i+1]){
evRight.push(data[i+1]);
}
}
$scope.tarjetasLeft = evLeft;
$scope.tarjetasRight = evRight;
})
You said you cannot interact with the modal view.
Try the option noBackdrop (or even maybe hideOnStateChange)
More info at the docs

Class prefix as selector for each function

I am able to do this using an ID prefix as the selector, but I need to be able to do it with classes instead. It's an each function for opening up different modal windows on the same page. I need to avoid using ID names because I have some modal windows that will have multiple links on the same page, and when using IDs, only the first link will work.
So here's the function as it works with IDs:
$('div[id^=ssfamodal-help-]').each(function() {
var sfx = this.id,
mdl = $(this),
lnk = $('.link-' + sfx),
cls = $('.ssfamodal-close'),
con = $('.ssfamodal-content');
lnk.click(function(){
mdl.show();
});
cls.click(function(){
mdl.hide();
});
mdl.click(function() {
mdl.hide();
});
con.click(function() {
return false;
});
});
and I'm trying to change it to classes instead, like:
$('div[class^=ssfamodal-help-]').each(function() {
var sfx = this.attr('class'),
etc.
But I cannot get it to work without using IDs. Is it possible?
EDIT Fixed error with semi-colon at end of Vars, and updated Fiddle with the fix. Still not working though.
Here's a Fiddle
** UPDATE **
To be clearer, I need to be able to refer to the same modal more than once on the same page. E.g.:
MODAL 1
MODAL 2
MODAL 3
MODAL 4
LINK TO MODAL 1
LINK TO MODAL 2
LINK TO MODAL 3
LINK TO MODAL 4
OTHER STUFF
LINK TO MODAL 1
LINK TO MODAL 4
LINK TO MODAL 3
OTHER STUFF
LINK TO MODAL 2
ETC.
When using classes get rid of the ID habit :
className1, className2, className3 ... etc
simply use
className
HTML:
<div class="ssfamodal-help-base ssfamodal-backdrop">
<div id="help-content" class="ssfamodal-content">
<span class="ssfamodal-close">[x]</span>
Howdy
</div>
</div>
<div class="ssfamodal-help-base ssfamodal-backdrop">
<div id="help-content" class="ssfamodal-content">
<span class="ssfamodal-close">[x]</span>
Howdy Ho
</div>
</div>
<span class="link-ssfamodal-help-base">One</span>
<span class="link-ssfamodal-help-base">Two</span>
LIVE DEMO
var $btn = $('.link-ssfamodal-help-base'),
$mod = $('.ssfamodal-help-base'),
$X = $('.ssfamodal-close');
$btn.click(function(i) {
var i = $('[class^="link-"]').index(this); // all .link-** but get the index of this!
// Why that?! cause if you only do:
// var i = $('.link-ssfamodal-help-base').index();
// you'll get // 2
// cause that element, inside a parent is the 3rd element
// but retargeting it's index using $('className').index(this);
// you'll get the correct index for that class name!
$('.ssfamodal-help-base').eq(i).show() // Show the referenced element by .eq()
.siblings('.ssfamodal-help-base').hide(); // hide all other elements (with same class)
});
$X.click(function(){
$(this).closest('.ssfamodal-help-base').hide();
});
From the DOCS:
http://api.jquery.com/eq/
http://api.jquery.com/index/
http://api.jquery.com/closest/
Here I created a quite basic example on how you can create a jQuery plugin of your own to handle modals: http://jsbin.com/ulUPIje/1/edit
feel free to use and abuse.
The problem is that class attributes can consist of many classes, rather than IDs which only have one value. One solution, which isn't exactly clean, but seems to work is the following.
$('div').filter(function () {
var classes = $(this).attr('class').split(/\s+/);
for (var i = 0; i < classes.length; i++)
if (classes[i].indexOf('ssfamodal-help-') == 0)
return true;
return false;
}).each(function() {
// code
});
jsFiddle
Or, equivalently
$('div').filter(function () {
return $(this).attr('class').split(/\s+/).some(function (e) {
return e.indexOf('ssfamodal-help-') == 0;
});
}).each(function() {
// code
});
jsFiddle
If there is one-to-one relationship between the modal helps and the modal links which it appears there is...can simplfy needing to match class values by using indexing.
For this reason you don't need unique class names, rather they just overcomplicate things. Following assumes classes stay unique however
var $helps=$('div[id^=ssfamodal-help-]');
var $help_links=$('div[id^=link-ssfamodal-help-]');
$help_links.click(function(){
var linkIndex= $help_links.index(this);
$helps.hide().eq( linkIndex ).show();
});
/* not sure if this is what's wanted, but appeared original code had it*/
$helps.click(function(){
$(this).hide()
})
/* close buttons using traverse*/
$('.ssfamodal-close').click(function(){
$(this).closest('div[id^=ssfamodal-help-]' ).hide();
});
Also believe that this code is a little more readable than original apporach
DEMO
Can you try this,
$('div[class^=ssfamodal-help-]').each(function() {
var sfx = $(this).attr('class');
console.log(sfx);
/*console log:
ssfamodal-help-base ssfamodal-backdrop
ssfamodal-help-base2 ssfamodal-backdrop
*/
});
Demo: http://jsfiddle.net/xAssR/51/
why don't you write like
$('div.classname').each(function() {
// you can write your desired code here
var sfx = this.attr('class');
var aa= this.attr('id');
});
or
$('.classname').each(function() {
// you can write your desired code here
var sfx = this.attr('class');
var aa= this.attr('id');
});
where classname is the name of the class used for the div in html
Thanks.

Angular app wont load (JSFiddle)

I have a simple angular app here
<div ng-app="WhereToMeet" ng-controller="MapCtrl">
<leaflet shape="shape"></leaflet>
<button ng-click="clicked()">Clicked</button>
</div>
app = angular.module("WhereToMeet", [])
app.directive "leaflet", ->
restrict: "E"
replace: true
transclude: true
template: "<div id=\"map\"></div>"
scope:
shape: "=shape"
link: (scope, element, attrs, ctrl) ->
scope.$watch attrs.shape,( (newValue, oldValue) ->
watched newValue
), true
watched = (newValue) ->
alert newValue
#MapCtrl = ($scope) ->
clicked = (clicked) ->
$scope.shape = "Clicked"
alert "clicked"
I have it in a JSFiddle http://jsfiddle.net/charliedavi/bezFB/22/ but it wont run. Really odd. I think its an error with my coffee script but I can not see it
error:
Uncaught SyntaxError: Unexpected string fiddle.jshell.net:22
Uncaught Error: No module: WhereToMeet
in pure JS
var app;
app = angular.module("WhereToMeet", []);
app.directive("leaflet", function() {
var watched;
({
restrict: "E",
replace: true,
transclude: true,
template: "<div id=\"map\"></div>",
scope: {
shape: "=shape"
},
link: function(scope, element, attrs, ctrl) {
return scope.$watch(attrs.shape, (function(newValue, oldValue) {
return watched(newValue);
}), true);
}
});
return watched = function(newValue) {
return alert(newValue);
};
});
this.MapCtrl = function($scope) {
var clicked;
return clicked = function(clicked) {
$scope.shape = "Clicked";
return alert("clicked");
};
};
http://jsfiddle.net/charliedavi/gsPx3/2/
i dont know coffee script but angular. i just tried to solve it. ;-)
Select no-wrap body, under select framework
Select no-library(pure-js)
Add angular js as resources
Manually initialize angular using this angular bootstrap
angular.bootstrap document, ['WhereToMeet']
The generated javascript code is in another scope. You have to solve this
by either adding the -b parameter to the coffeescript compiler or export your function
explicitly via
root = exports ? this
root.clicked = ->
alert "clicked"
$scope.shape = "Clicked"
It is working now Fiddle Here
I had a similar issue with jsfiddle and angular yesterday. I had to do a couple of things to make it work:
Jsfiddle is adding the tags for html and body, so just write the markup that should end up inside the body tag.
Add a wrapping div with ng-app="myApp" instead of trying to specify another html-tag
Select no-wrap body, under select framework
I don't know what your "leaflet" is doing but I have updated your fiddle so that the click will trigger an alert
I've had to change the how the controller is instantiated to get the onclick to work.
http://jsfiddle.net/t9nsY/2/
app.controller("MapCtrl", function ($scope) {
$scope.clicked = function (clicked) {
console.log("clicked");
$scope.shape = "Clicked";
return alert("clicked");
};
});