angularjs : disable a button and show popup instead - angularjs

I have this button :
html:
<button nav-direction="back" class="button yy" ui-sref="app.result" ui-sref-active="currentNav" ng-click="navResult()">
Board
</button>
I would like it to display a popup if a certain condition is, else I would like it to go to another page.
I need to keep the benefit of the class in ui-sref-active to show that this is the current page.
controller.js
$scope.navResult = function (){
console.log(sessionService.get('computed'));
if (sessionService.get('computed')) {
$scope.go('app.result');
} else {
//popup to user to tap on a board
//$scope.go('app.compute');
var popupConfig = {
title: 'Beware! ;)',
template: 'Tap on a board below'
};
var popup = $ionicPopup.show(popupConfig);
ClosePopupService.register(popup);
}
}
$scope.go = function ( state ) {
// console.log("go has been launched with : "+ state)
$state.go( state );
};

Simple. You just use an ng-click method instead of a ui-sref, and go to the state from there.
<button nav-direction="back" ng-class="{'your-class':classCondition}" class="button yy" ng-click="navResult()">
Board
</button>
Then in your controller....
$scope.navResult = function(){
if(something){
$scope.classCondition = false;
//code to display popup here
} else {
$state.go('app.result')
}
}
You can pass any valid state into $state.go, so if you ever want to check for a condition and perform some logic BEFORE you redirect to another page, use it inside a $scope method instead of just using the straight ui-sref.

Related

angular: view not being updated when data changes in another controller

Basically it's simple, but I can't make it work.
Note: using ionic.
I have:
a view and controller for pre-defined Playlists
a view and controller for UserPlaylists.
a ionic popover for assigning a song to a UserPlaylist.
It should work like this:
I look at songs in the pre-defined Playlists. I choose a song to be added to a UserPlaylist. The popover appears, allowing to choose the UserPlaylist to add the song to. I select it and the song gets added to the UserPlaylist. The app remains in the pre-defined playlist view.
It all works. Except the view with the UserPlaylist does not get updated when I switch back to it with the new song - I need to RELOAD the UserPlaylist view, and then I can see the new song added...
I could NOT use $apply(), is it would always tell me it's already in process. Is ionic or angular somehow caching things?
The playlist html
<div ng-hide="loading">
<h2>{{playlist.name}}
<button on-tap="addAllToUserPlaylist()" class="small add-to-playlist"></button>
<button on-tap="addAllToQueue()" class="small add-to-queue"></button>
<button on-tap="playAll()" class="small play"></button>
</h2>
<app-song can-like="true" can-add-to-queue="true" can-add-to-playlist="true" on-select="tappedSong(song)" item="song" ng-repeat="song in playlist.songs" />
</div>
</ion-content>
The add to playlist code in the song directive
/**
* AddToPlaylist button was tapped
*/
function addToPlaylist(e){
e.stopPropagation();
// Show add to playlist template as a popover.
// Note that we're passing this directive's scope
// as the popover's parent scope. That way the popover's
// controller will have access to the variables here.
// Also, we're putting a reference to the popover in
// scope.popover so we can access it later to destroy it.
$ionicPopover.fromTemplateUrl('templates/add.to.playlist.html',{
animation: 'slide-in-up',
scope: scope,
backdropClickToClose: false
}).then(function(popover){
scope.popover = popover;
popover.show();
});
}
the UserPlaylist code:
UserPlaylistDataSource.prototype.addSongs = function(songs, id, beginning, cbk){
if(beginning){
Array.prototype.unshift.apply(this.songs, songs);
}
else{
Array.prototype.push.apply(this.songs, songs);
}
this.save(id, cbk);
}
the popover add code:
$scope.add = function(playlist){
var toAdd;
var msg = 'Agregaste $1 a la lista ' + playlist.name;
// If the parent scope has an 'item' it is the song they want to add
if($scope.item){
toAdd = [$scope.item];
msg = msg.replace('$1', 'una canción');
}
// If the parent scope has a 'playlist' add all of it's songs
else if($scope.playlist){
toAdd = $scope.playlist.songs;
msg = msg.replace('$1', $scope.playlist.songs.length+' canciones');
}
// If the parent scope has a 'queue' add all of it's songs
else if($scope.queue){
toAdd = $scope.queue.songs;
msg = msg.replace('$1', $scope.queue.songs.length+' canciones');
}
$scope.loading = true;
playlist.addSongs(toAdd, playlist.id, false, function(err){
$scope.loading = false;
//HERE playlist has the correct number of songs! So it worked!
if($scope.item) $scope.unflip(); // if parent scope is a single song.
$scope.close();
if (err) {
return MessageService.show(err);
}
MessageService.show(msg);
});
};
the popover html:
<ion-scroll>
<h3 on-tap="newPlaylist()"><img src="/img/icon-round-add.png"/> <span>Crear Nueva Lista de Reproducción</h3>
<div class="spinner-container" ng-show="loading"><ion-spinner></ion-spinner></div>
<br/>
<h3 class="playlist" ng-repeat="playlist in playlists" on-tap="add(playlist)"><img ng-src="{{playlist.client_data.icon_url}}"/> <span>{{playlist.name}}</span></h3>
</ion-scroll>
I fixed by reading this:
http://ionicframework.com/docs/api/directive/ionView/
and putting
<ion-view cache-view="false">
at the UserPlaylist view

Enable and disable CKEditor Inline editing using Angular

How can I enable or disable ckeditor.inline on a div based on a click of a button/link.
This is how I would achieve it in jquery but can't figure it out using angular.
$('.toggle-edit').click(function(e){
var id_editedDiv = $(this).data('editTarget');
var editedDiv = '#' + id_editedDiv;
if( $(editedDiv).attr('contenteditable') == 'true' )
{
$(editedDiv).attr('contenteditable','false');
CKEDITOR.instances.id_editedDiv.destroy();
$(this).text('Start Editing');
}
else
{
$(editedDiv).attr('contenteditable','true');
CKEDITOR.inline( id_editedDiv );
$(this).text('Finish Editing');
}
});
This is how I achieved the result.
https://plnkr.co/edit/YUOYGa?p=preview
But now I need to figure out how to bind the model to the CKEditor so that my changes are updated in the model when I hit save.
Destroys the editor instance, releasing all resources used by it. If the editor replaced an element, the element will be recovered.
In your controller:
alert( CKEDITOR.instances.editor1 ); // e.g. object
CKEDITOR.instances.editor1.destroy();
alert( CKEDITOR.instances.editor1 ); // undefined
More detail
You can use button with ng-click attribute for example:
<button type="button" class="inlineEditButton"
ng-controller="CKEditorController"
ng-click="changeInlineEditindState()"
</button>
in CKEditorController you should define method:
$scope.changeInlineEditindState = function() {
// your code
}
You can do something like:
var content = '';
After instances creation add listener:
ck.on('instanceReady', function () {
ck.setData(content);
});
On save button click:
content = ck.getData();

Creating a "Like" button with Angular.js

Im trying to create a like button with Angular.js.
(It is just a heart icon. default color is white = NOT liked. It is red when liked. Like/unlike is toggled by a click)
I get some data from my web service that has also an array of some ID's. These ID's are the ones that clicked the like button before.
Then i populate the DOM with the ng-repeat directive according to the data retrieved from the web service.
I attach the button a ng-class that sets the proper class and a ng-click directive that is supposed to somehow change the class too.
* I cant connect between the ng-class and the ng-click result.
some code:
<div ng-repeat="photo in photos track by photo._id">
<button ng-class="{carouselFooterButtonLikeActive : initLike(photo)}" ng-click="like(photo, this)">
<i class="icon ion-heart"></i>
</button>
</div>
Controller:
// Handle like button click
$scope.like = function(photo, photoScope){
HOW CAN I AFFECT THE NG-CLASS FROM HERE?
}
$scope.initLike = function(photo){
if(photo.likes.indexOf($localstorage.getObject('userInfo').id) > -1) {
$scope.liked = true;
return true;
}
$scope.liked = false;
return false;
}
Edit: added a possible data retrieved from the web service
{
photos: [
{
src: "src1.jpg",
likes:[111,222,333]
},
{
src: "src2.jpg",
likes:[]
}
]
}
You can use as a flag some additional property that will be initially undefined on each photo element - say photo.liked. When user clicks it, $scope.like function sets this property to true. Then ng-class evaluates photo.liked to true and adds carouselFooterButtonLikeActive class to button element.
The code is as follows:
In the template:
<button ng-class="{'carouselFooterButtonLikeActive' : photo.liked}" ng-click="like(photo, this)">
In the controller:
$scope.like = function(photo, photoScope){
photo.liked = true;
}
UPD
Say you have photos array:
[
{'src':'bla-bla.jpg', liked: true, id: 8347},
{'src':'foo-bar.jpg', id: 45},
{'src':'baz-baz.jpg', id: 47}
]
then only the first one will be shown with button.carouselFooterButtonLikeActive class, thanks to ng-class evaluation expression.
UPD2
If photo.likes is an array, you can use:
//template
ng-class="{'carouselFooterButtonLikeActive' : (photo.likes && photo.likes.length >0)}"
//controller
$scope.like = function(photo, photoScope){
photo.likes.push(someUserID);
}

AngularJS - Manage button or input availability via model

So, i'm quite stuck at this:
I have quite many buttons on my page, each button's availability is different in different context, for example:
When button "Add" is pressed, its state will be "disabled", Cancel and Save buttons will be available.
I came up with a solution to manage the stage of every buttons in one object call state, like this:
// This is the Controller
$scope.some_id = false;
// With some UI interaction, $scope.some_id will be some integer value
$scope.getContextBtnAdd = function(){ return $scope.some_id; };
$scope.getContextBtnCancel = function(){ return !$scope.getContextBtnAdd(); };
$scope.state = {
contextBtns : {
btnAdd : $scope.getContextBtnAdd(),
btnCancel: $scope.getContextBtnCancel(),
},
footerBtns : { Some footer buttons }
};
// This is the View
<button name="add" ng-disabled="!state.contextBtns.btnAdd">Add</button>
"So when there is no product load, $scope.some_id will be false, so Add button will be available, but when user clicks on some products, the $scope.some_id will be some integer value like 4,7 or 100... and the button will be disabled. " <=== That's what i want. But actually it doesn't work, the some_id changes but maybe the getContext function is never called. Right now i have to pass the getContext function to ng-disabled like this:
<button name="add" ng-disabled="!getContextBtnAdd()">Add</button>
But i want to manage them all via one object. So what's is my code problem and is there any better way to manage button, input....s availabilities?
Thank you!
When that line is executed:
$scope.state = {
contextBtns : {
btnAdd : $scope.getContextBtnAdd(),
btnCancel: $scope.getContextBtnCancel(),
},
footerBtns : { Some footer buttons }
};
the state object is created, and its contextBtns.btnAdd attribute (for example) takes the value returned by $scope.getContextBtnAdd() at that time. The attribute value never changes after.
What you want instead is something that always has the value of $scope.getContextBtnAdd() every time it's evaluated. So you simply need the function itself:
$scope.state = {
contextBtns : {
btnAdd : $scope.getContextBtnAdd,
btnCancel: $scope.getContextBtnCancel,
},
footerBtns : { Some footer buttons }
};
and in the view:
<button name="add" ng-disabled="!state.contextBtns.btnAdd()">Add</button>

Adding an active class on ng-click function

I have 2 buttons and I just want to add a class when the button has been clicked.
<button class="panel-btn"
ui-sref="basechat"
ng-click="setBaseChat()" id="base-chat-btn">Base Chat</button>
<button class="panel-btn"
ui-sref="banner"
ng-click="setBannerChat()"
id="banner-chat-btn">Banner</button>
The function on ng-click returns a true value.
Hope you guys can help me, I still don't understand very well how ng-class works
If you want to add a class to a button on click you can do something like this:
<button ng-class="{someClass: someTruthyValue}" ng-click="someFunction()">
The ng-class will look at the value of someTruthyValue and display someClass if it is True, and not otherwise.
For example, your JS could look something like:
$scope.someTruthyValue = False;
$scope.someFunction = function() {
$scope.someTruthyValue = True;
}
The docs are fairly good here
Also, as you can see in the other answers, there is more than 1 way to use ng-class, however I like my solution because it allows you the option to link additional button to reverse the class change:
<button ng-click="someReverseFunction()">
Where, certainly:
$scope.someReverseFunction = function() {
$scope.someTruthyValue = False;
}
As a simple example, you could have:
$scope.bannerClass = "baseClass"; // baseClass defined in your CSS
$scope.setBannerChat = function() {
$scope.bannerClass = "myClass"; // myClass defined in your CSS
// or $scope.bannerClass = "baseClass myClass";
}
and then:
<div ng-class="bannerClass">Hello</div>
<button ng-click=setBannerChat()></button>
You can do this in your controller:
$scope.clickFucntion = function(){
$scope.myClass = 'my-class';
}
and this in your view:
<button class="{{myClass}}" ng-click="clickFucntion()">

Resources