Submitting the modal popUp overriding the data - html

I am trying to create timeline with a create timeline button. If create button is clicked a popUp opens and one need to select any of the item and the item will add one event to the timeline.
Here is the button and timeline 'div' where the new event will be added:
<center><button type="button" class="btn btn-primary" ng-click="showRoutinePopUp()">Let's create routine</button></center>
<section id="cd-timeline" class="cd-container">
<!--<routinepopup></routinepopup>-->
</section>
And here is the popup:
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
{{ item }}
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
And here is the angular code that is apepeding the popUp selected item to timeline :
modalInstance.result.then(function (selectedItem) {
el = $compile('<div class="cd-timeline-block" >' +
'<div class="cd-timeline-img cd-picture">' +
'<img src="img/cd-icon-picture.svg" alt="Picture">' +
'</div>' +
'<div class="cd-timeline-content">' +
'<h2>{{selected}}</h2>' +
'<p>{{selected}}</p>' +
'{{selected}}' +
'<span class="cd-date">{{selected}}</span>' +
'</div>' +
'</div>')($scope);
$scope.selected = selectedItem;
angular.element(document.getElementById('cd-timeline')).append(el);
The problem is whenever a new event is added through Popup, it overrides the previous added event also.
Go through this Plnkr : http://plnkr.co/edit/C5LivW?p=preview

The reason your new event is overwriting the previous event is:
Your selected variable is declared on the same $scope each time, so each item in the list is referencing to the same object, in your case they are all referencing to the last event added.
Some advice: You should rather use the ng-repeat directive to show items in a list.
The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.
I have updated your plunker to show you an example, its not complete but it shows the wanted behavior.
Here is the updated HTML:
<section class="cd-container">
<div class="cd-timeline-block" data-ng-repeat="event in events">
<div class="cd-timeline-img cd-picture">
<img src="img/cd-icon-picture.svg" alt="Picture">
</div>
<div class="cd-timeline-content">
<h2>{{event}}</h2>
<p>{{event}}</p>
{{event}}
<span class="cd-date">{{event}}</span>
</div>
</div>
</section>
and the updated JS:
app.controller('appController', function($scope, $uibModal, $log, $compile) {
$scope.events = [];
var count = 0;
console.log('inside controller');
$scope.items = ['item1', 'item2', 'item3'];
$scope.animationsEnabled = true;
$scope.showPopUp = function(size) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'PopUp.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function() {
return $scope.items;
}
}
});
modalInstance.result.then(function(selectedItem) {
$scope.events.push(selectedItem);
//angular.element(document.getElementById('cd-timeline')).append(el);
count++;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
});

Better use ng-repeat to show tasks and on modal resolve only push selected task to selectedItems array, now in all your blocks you point to {{selected}} which changes in modal resolve function thats why all your tasks rewrites.

Related

Angular JS - Modal not shown properly

I am learning to use Modal in AngularJS and Bootstrap 4 framework. I have manage to show it, but it is not shown properly, i.e. blocking components in background and cannot be shown if animation: true. I am not sure what causing this because I have inject ngAnimate and ui.bootstrap in my app controller.
Angular and ui-bootstrap version used
Angular v1.6.4
UI-bootstrap v2.5.0
Below I will provide my code.
View.html
<div class="container-fluid content-container" ng-app="listEmployee">
<div class="change-password-modal-container"></div>
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title" id="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body" id="modal-body">
<ul>
<li ng-repeat="item in ctrl.items">
{{ item }}
</li>
</ul>
Selected: <b>{{ ctrl.selected.item }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ctrl.ok()">OK</button>
<button class="btn btn-warning" type="button" ng-click="ctrl.cancel()">Cancel</button>
</div>
</script>
... <!--other html elements -->
</div>
Below is my code in controller which is related to showing the modal
Controller.js
var ctrl = this;
ctrl.items = ['item1', 'item2', 'item3'];
ctrl.animationsEnabled = false;
ctrl.open = function (size, parentSelector) {
var parentElem = parentSelector ?
angular.element($document[0].querySelector('.change-password-modal-container ' + parentSelector)) : undefined;
var modalInstance = $uibModal.open({
animation: ctrl.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
controllerAs: 'ctrl',
size: size,
appendTo: parentElem,
resolve: {
items: function () {
return ctrl.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
ctrl.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
The z-index of my content is 1
mystyle.css
#content {
z-index: 1;
}
Below is the screenshot when the animation:false
Below is the screenshot when the animation:true (i.e. modal is not visible, it's like the modal is behind the screen)
Any help would be appreciated.
After reading this issue in GitHub, turns out this is the problem when using Bootstrap 4. Bootstrap 4 has different class names with Bootstrap 3, in this case, it is .in in version 3 become .show in version 4.
Following as suggested by IdanCo in the thread, which I rewrite below (so it will be easier for others to read) fixed this issue.
Change the class names from ui-bootstrap-tpls-###.js as below.
'class': 'modal-backdrop',
'ng-style': '{\'z-index\': 1040 + (index && 1 || 0) + index*10}',
'uib-modal-animation-class': 'fade',
'modal-in-class': 'in' //change this
'modal-in-class': 'show' //to this
});
if (modal.backdropClass) {
backdropDomEl.addClass(modal.backdropClass);
## -477,7 +477,7 ##
'ng-style': '{\'z-index\': 1050 + $$topModalIndex*10, display: \'block\'}',
'tabindex': -1,
'uib-modal-animation-class': 'fade',
'modal-in-class': 'in' //change this
'modal-in-class': 'show' //to this
}).append(content);
if (modal.windowClass) {
angularDomEl.addClass(modal.windowClass);
Hope this update could help someone in the future.

How to hide button in ng-repeat in AngularJS?

My View:
<div class="col-sm-4 col-xs-4" ng-repeat="(id, object) in objects">
<button type="primary"
ng-click="add(id)"
ng-hide="id.plz" style="color: cyan;">Add</button>
</div>
Controller JavaScript:
$scope.add = function(id){
// some function;
$scope.objects[id].plz = true;
}
Any idea why it won't work?
<div class="col-sm-4 col-xs-4" ng-repeat="(id, object) in objects">
<button type="primary" ng-hide="objects[id].plz" ng-click="add(id)" style="color: cyan;" >Add</button>
<div>
here in ng-hide="id.plz" id is the index so there is no id.plz
learn more about ng-hide and alternatives here
If you want to conditionally hide your button in ng-repeat, use ng-hide, ng-show(if there is a chance that you will hide and show it later) or ng-if(if it's a one time hide of button).
ng-hide takes a boolean and shows/displays accordingly. In your case your ng-hide is always turned out to be true, so you are unable to hide. Just write the condition required in your ng-hide to hide your button
Hide the button when its clicked like in this fiddle:
View
<div ng-controller="MyCtrl">
<div ng-repeat="user in data">
{{ user.name}}
<button ng-hide="hide[$index]" ng-click="add();hide[$index] = true;">
Add
</button>
</div>
</div>
AngularJS application
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope) {
$scope.add = function () {
console.log('add');
}
$scope.data = [{
name: 'frank'
},{
name: 'peter'
},{
name: 'melanie'
},{
name: 'sven'
},{
name: 'basti'
},{
name: 'edjuh'
}];
});

ng-show doesn't change on routeChange in AngularJS

I am developing an website with AngularJS and
mobile angular UI.
I have a menu bar which will show on clicking a button and should be closed when I click the options in it. But it isn't working as expected.
My files:
index.html
<div id="menuBar" ng-show="showMenu">
<div class="row">
page1
</div>
</div>
js for hiding menu
app.controller('mainController', function ($rootScope, $scope) {
$rootScope.showMenu = false;
$rootScope.$on("$routeChangeStart", function () {
$rootScope.showMenu = false;
});
});
So while switching to some other file the menu should hide ideally. But it didn't happen so.
The problem is how you show your menu. With this code:
<div ng-click="showMenu=!showMenu" class="btn btn-navbar"><i class="fa fa-bars"></i></div>
you change showMenu property of the child scope. This showMenu is not the same as $rootScope.showMenu. For this reason when you change $rootScope.showMenu in $routeChangeStart it doesn't effect child scope property. Instead you should do something like this:
<div ng-click="toggleMenuBar()" class="btn btn-navbar"><i class="fa fa-bars"></i></div>
and in controller:
$scope.toggleMenuBar = function() {
$rootScope.showMenu = !$rootScope.showMenu;
};

How to use ng-show and ng-hide with buttons in AngularJS

I have two buttons Start and Stop,when I click the Start button I want the Stop button to show and the Start button to be hidden vice versa when I click the Stop button I want the Start button to be shown and the Stop button to be hidden.Only one button must be shown at any one time.Here is what I tried but it doesn't seem to work.Where am I going wrong?
<span ng-hide="Model.StartEvent == true">
<button ng-click="Model.StartEvent()" id="btnEventStart">Start</button>
</span>
<span ng-show="Model.StopEvent == false">
<button ng-click="Model.StopEvent()" id="btnStopEvent" class="tooltip">Stop</button>
</span>
You could do even less
<button ng-click="goEvent();" ng-hide="going">Start</button>
<button ng-click="goEvent();" ng-show="going">Stop</button>
...
$scope.going = false;
$scope.goEvent = function(){
$scope.going = !$scope.going;
if($scope.going){
$scope.go();
}else{
$scope.stop();
}
}
you should use same variable for both...
<button ng-click="Model.toggleShow(); Model.StartEvent()" ng-show="Model.showStartEvent">Start</button>
<button ng-click="Model.toggleShow(); Model.StopEvent()" ng-show="!Model.showStartEvent">Stop</button>
Modal.toggleShow = function(){
Model.showStartEvent = !Model.showStartEvent;
}
also you can call toggle right inside the startevent/stopevent rather than having two function calls on ng-click
Html:
<div ng-controller="YourController">
<span ng-hide="EventRunning"><button ng-click="StartEvent($event)"id="btnEventStart">Start</button></span>
<span ng-show="EventRunning"><button ng-click="StopEvent($event)" id="btnStopEvent">Stop</button></span>
</div>
Use single semaphore for hide and show EventRunning
Controller:
{ ...
$scope.EventRunning = false;
$scope.StartEvent = function (event) {
event.preventDefault();
$scope.EventRunning = true;
// your code
}
$scope.StopEvent = function (event) {
event.preventDefault();
$scope.EventRunning = false;
// your code
}
... }

Edit In Place Content Editing

When using ng-repeat what is the best way to be able to edit content?
In my ideal situation the added birthday would be a hyperlink, when this is tapped it will show an edit form - just the same as the current add form with an update button.
Live Preview (Plunker)
HTML:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script src="app.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.0/css/bootstrap-combined.min.css"
rel="stylesheet">
</head>
<body ng-app="birthdayToDo" ng-controller="main">
<div id="wrap">
<!-- Begin page content -->
<div class="container">
<div class="page-header">
<h1>Birthday Reminders</h1>
</div>
<ul ng-repeat="bday in bdays">
<li>{{bday.name}} | {{bday.date}}</li>
</ul>
<form ng-show="visible" ng-submit="newBirthday()">
<label>Name:</label>
<input type="text" ng-model="bdayname" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bdaydate" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
</form>
</div>
<div id="push"></div>
</div>
<div id="footer">
<div class="container">
<a class="btn" ng-click="visible = true"><i class="icon-plus"></i>Add</a>
</div>
</div>
</body>
App.js:
var app = angular.module('birthdayToDo', []);
app.controller('main', function($scope){
// Start as not visible but when button is tapped it will show as true
$scope.visible = false;
// Create the array to hold the list of Birthdays
$scope.bdays = [];
// Create the function to push the data into the "bdays" array
$scope.newBirthday = function(){
$scope.bdays.push({name:$scope.bdayname, date:$scope.bdaydate});
$scope.bdayname = '';
$scope.bdaydate = '';
};
});
You should put the form inside each node and use ng-show and ng-hide to enable and disable editing, respectively. Something like this:
<li>
<span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
</form>
</li>
The key points here are:
I've changed controls ng-model to the local scope
Added ng-show to form so we can show it while editing
Added a span with a ng-hide to hide the content while editing
Added a ng-click, that could be in any other element, that toggles editing to true
Changed ng-submit to toggle editing to false
Here is your updated Plunker.
I was looking for a inline editing solution and I found a plunker that seemed promising, but it didn't work for me out of the box. After some tinkering with the code I got it working. Kudos to the person who made the initial effort to code this piece.
The example is available here http://plnkr.co/edit/EsW7mV?p=preview
Here goes the code:
app.controller('MainCtrl', function($scope) {
$scope.updateTodo = function(indx) {
console.log(indx);
};
$scope.cancelEdit = function(value) {
console.log('Canceled editing', value);
};
$scope.todos = [
{id:123, title: 'Lord of the things'},
{id:321, title: 'Hoovering heights'},
{id:231, title: 'Watership brown'}
];
});
// On esc event
app.directive('onEsc', function() {
return function(scope, elm, attr) {
elm.bind('keydown', function(e) {
if (e.keyCode === 27) {
scope.$apply(attr.onEsc);
}
});
};
});
// On enter event
app.directive('onEnter', function() {
return function(scope, elm, attr) {
elm.bind('keypress', function(e) {
if (e.keyCode === 13) {
scope.$apply(attr.onEnter);
}
});
};
});
// Inline edit directive
app.directive('inlineEdit', function($timeout) {
return {
scope: {
model: '=inlineEdit',
handleSave: '&onSave',
handleCancel: '&onCancel'
},
link: function(scope, elm, attr) {
var previousValue;
scope.edit = function() {
scope.editMode = true;
previousValue = scope.model;
$timeout(function() {
elm.find('input')[0].focus();
}, 0, false);
};
scope.save = function() {
scope.editMode = false;
scope.handleSave({value: scope.model});
};
scope.cancel = function() {
scope.editMode = false;
scope.model = previousValue;
scope.handleCancel({value: scope.model});
};
},
templateUrl: 'inline-edit.html'
};
});
Directive template:
<div>
<input type="text" on-enter="save()" on-esc="cancel()" ng-model="model" ng-show="editMode">
<button ng-click="cancel()" ng-show="editMode">cancel</button>
<button ng-click="save()" ng-show="editMode">save</button>
<span ng-mouseenter="showEdit = true" ng-mouseleave="showEdit = false">
<span ng-hide="editMode" ng-click="edit()">{{model}}</span>
<a ng-show="showEdit" ng-click="edit()">edit</a>
</span>
</div>
To use it just add water:
<div ng-repeat="todo in todos"
inline-edit="todo.title"
on-save="updateTodo($index)"
on-cancel="cancelEdit(todo.title)"></div>
UPDATE:
Another option is to use the readymade Xeditable for AngularJS:
http://vitalets.github.io/angular-xeditable/
I've modified your plunker to get it working via angular-xeditable:
http://plnkr.co/edit/xUDrOS?p=preview
It is common solution for inline editing - you creale hyperlinks with editable-text directive
that toggles into <input type="text"> tag:
<a href="#" editable-text="bday.name" ng-click="myform.$show()" e-placeholder="Name">
{{bday.name || 'empty'}}
</a>
For date I used editable-date directive that toggles into html5 <input type="date">.
Since this is a common piece of functionality it's a good idea to write a directive for this. In fact, someone already did that and open sourced it. I used editablespan library in one of my projects and it worked perfectly, highly recommended.