Angular 2 bootstrap modal pass data - angularjs

I am newbie on angular 2. I am trying to do simple crud operations. However I have problem with using bootstrap modal. The code below, opens bootstrapmodal but I can't send selected movie on DeleteMovie() method.
<div style="margin: 20px">
<h2>Movies List</h2>
<input type="button" Value="Add Movie" class="btn btn-primary" (click)="AddMovie()"/>
<hr/>
<div class="row">
<div class="col-md-12">
<table class="table table-bordered">
<thead>
<tr>
<th>Movie Name</th>
<th>Genre</th>
<th>Edit</th>
<th>Delete</th>
<th>Delete2</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let mv of movies">
<td>{{mv.MovieName}}</td>
<td>{{mv.MovieGenre}}</td>
<td><a routerLink="/movies/{{mv.movieID}}"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><i class="glyphicon glyphicon-remove clickable" (click)="removeMovie(mv)"></i></td>
<td><i class="glyphicon glyphicon-remove clickable" data-toggle="modal" data-target="#myModal2" data-id="{{mv.MovieName}}" (click)="SelectMovie(mv)"></i></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="modal fade" id="myModal2" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Delete Record</h4>
</div>
<div class="modal-body">
Do you want to delete {{selectedMovie.MovieName}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" (click)="removeMovieV2(selectedMovie)" data-dismiss="modal">Delete</button>
</div>
</div>
</div>
</div>
#Component({
selector: 'movies2',
templateUrl: '/templates/movies.component.html',
providers: [MoviesService]
})
export class MoviesComponent implements OnInit {
isLoading = true;
movies: any = [];
selectedMovie:any={};
constructor(private _moviesService: MoviesService, private router: Router, private notificationService: NotificationService) {
}
ngOnInit() {
this.GetMovies();
}
AddMovie() {
this.router.navigate(['/newmovie']);
}
GetMovies() {
this._moviesService.getMovies().subscribe(p => {
this.movies = p;
});
}
SelectMovie(mv: any) {
this.selectedMovie = mv;
}
removeMovieV2(val: any) {
this._moviesService.deleteMovie(val).subscribe(res => {
this.notificationService.printSuccessMessage(val.MovieName + ' has been deleted.');
this.GetMovies();
}, error => {
this.notificationService.printErrorMessage(error);
});
}
}

I think you need to use attribute binding instead of property binding for boostrap to get the value
attr.data-id="{{mv.MovieName}}"
(only for strings)
or
[attr.data-id]="mv.MovieName"
(also supports objects)

Related

Pass table data into a method in angular

Here is my code:
<body ng-app="intranet_App" ng-controller="myCtrl">
<div class="container">
<div class="modal" id="deleteProject">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body" id="confirmMessage">
Are you sure do you want to delete this project??
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="confirmOk" ng-click="deleteProject(x.Id)">Ok</button>
<button type="button" class="btn btn-default" id="confirmCancel" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
<div class="col-xs-12 margin20 padding table-responsive">
<table class="col-xs-12 table table-hover table-bordered" id="projectList">
<thead class="colorBlue">
<tr><th>Project Name</th><th>Client</th><th>Client Co-ordinator</th><th>Action</th></tr>
</thead>
<tbody id="projectListTBody" >
<tr ng-repeat="x in projectList | filter:ProjectName">
<td>{{ x.ProjectName}}</td>
<td>{{ x.Client}}</td>
<td>{{ x.OnsiteCoordinator}}</td>
<td>
<i class="fa fa-user-plus fa-2x" ng-click="addResource()"></i>
<i class="fa fa-edit fa-2x" ng-click="editProj(x.Id)"></i>
<i class="fa fa-trash fa-2x" data-toggle="modal" data-target="#deleteProject"></i>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
<script>
var app = angular
.module("intranet_App", [])
.controller("myCtrl", function ($scope, $http) {
$scope.projDetails = [];
$http.post('/Project/getProjectsList')
.then(function (response) {
console.log(response)
$scope.projectList = response.data;
})
$scope.deleteProject = function (id) {
alert(id)
}
});
</script>
Here when I click delete icon in a table, I am displaying one bootstrap popup modal.In that modal I need to pass x.Id inside deleteProject method on the on click on ok button.But I am unable to hit the method,how to pass it?
In HTML code, add ng-click to delete button
<i class="fa fa-trash fa-2x" data-toggle="modal" data-target="#deleteProject" ng-click="delete(x.id)"></i>
In controller add following method
$scope.delete = function (id) {
$scope.deleteId = id;
}
Using that in deleteProject method
$scope.deleteProject = function () {
//use $scope.deleteId here
alert($scope.deleteId);
}
You're trying to access the x var outside of the ng-repeat in which it is defined it, so naturally, it won't know what x is. This is why you're getting undefined.
Here's the quickest solution I could come up with, there should be a better way, though:
<i class="fa fa-trash fa-2x"
data-toggle="modal"
data-target="#deleteProject"
ng-click="current = x"></i>
Which will assign the last clicked x into current. Then, you should refer to current inside the modal:
<button type="button"
class="btn btn-default"
id="confirmOk"
ng-click="deleteProject(current.Id)">
Ok
</button>

Retain checkbox selection on click of previous and next in the bootstrap modal

I've a bootstrap modal which contains a table of users.
I can select a user from the table and on clicking 'save', the details of seleced user is displayed.
I'm displaying 10 users per page in the table of the modal.
However, if I select any user from page 1 and then click next to select some users from page 2 and click on 'save', my selection from page 1 is not retained.
I mean the checkbox is cleared on page 1, whenever I click on next or previous.
How do I retain this selection on my checkbox, even if I click on next or previous at any page?
Here's the snippet:
var currentPageNo = 0; // Keep track of currently displayed page
// Select button that is descendant of userList
$('#userList .prev-btn').click(function(){
userList(currentPageNo-10);
});
$('#userList .next-btn').click(function(){
userList(currentPageNo+10);
});
$('#adminList .prev-btn').click(function(){
adminList(currentPageNo-10);
});
$('#adminList .next-btn').click(function(){
adminList(currentPageNo+10);
});
function userList(pageNo) {
var resType="userList";
createTable(resType,pageNo);
}
function adminList(pageNo) {
var resType="adminList";
createTable(resType,pageNo);
}
function createTable(resType, pageNo) {
// Update global variable
currentPageNo = pageNo;
// Set visibility of the correct "prev" button:
$('#' + resType + ' .prev-btn').toggle(pageNo > 0);
// Ask one record more than needed, to determine if there are more records after this page:
$.getJSON("https://api.randomuser.me/?results=11&resType="+resType + "&pageIndex=" + pageNo, function(data) {
var $table = $('#' + resType + ' table');
$('tr:has(td)', $table).empty();
// Check if there's an extra record which we do not display,
// but determines that there is a next page
$('#' + resType + ' .next-btn').toggle(data.results.length > 10);
// Slice results, so 11th record is not included:
data.results.slice(0, 10).forEach(function (record, i) { // add second argument for numbering records
var json = JSON.stringify(record);
$table.append(
$('<tr>').append(
$('<td>').append(
$('<input>').attr('type', 'checkbox')
.addClass('selectRow')
.val(json),
(i+1+pageNo) // display row number
),
$('<td>').append(
$('<a>').attr('href', record.picture.thumbnail)
.addClass('imgurl')
.attr('target', '_blank')
.text(record.name.first)
),
$('<td>').append(record.dob)
)
);
});
// Show the prev and/or buttons
}).fail(function(error) {
console.log("**********AJAX ERROR: " + error);
});
}
var savedData = []; // The objects as array, so to have an order.
function saveData(){
var errors = [];
// Add selected to map
$('input.selectRow:checked').each(function(count) {
// Get the JSON that is stored as value for the checkbox
var obj = JSON.parse($(this).val());
// See if this URL was already collected (that's easy with Set)
if (savedData.find(record => record.picture.thumbnail === obj.picture.thumbnail)) {
errors.push(obj.name.first);
} else {
// Append it
savedData.push(obj);
}
});
refreshDisplay();
if (errors.length) {
alert('The following were already selected:\n' + errors.join('\n'));
}
}
function refreshDisplay() {
$('.container').html('');
savedData.forEach(function (obj) {
// Reset container, and append collected data (use jQuery for appending)
$('.container').append(
$('<div>').addClass('parent').append(
$('<label>').addClass('dataLabel').text('Name: '),
obj.name.first + ' ' + obj.name.last,
$('<br>'), // line-break between name & pic
$('<img>').addClass('myLink').attr('src', obj.picture.thumbnail), $('<br>'),
$('<label>').addClass('dataLabel').text('Date of birth: '),
obj.dob, $('<br>'),
$('<label>').addClass('dataLabel').text('Address: '), $('<br>'),
obj.location.street, $('<br>'),
obj.location.city + ' ' + obj.location.postcode, $('<br>'),
obj.location.state, $('<br>'),
$('<button>').addClass('removeMe').text('Delete'),
$('<button>').addClass('top-btn').text('Swap with top'),
$('<button>').addClass('down-btn').text('Swap with down')
)
);
})
// Clear checkboxes:
$('.selectRow').prop('checked', false);
handleEvents();
}
function logSavedData(){
// Convert to JSON and log to console. You would instead post it
// to some URL, or save it to localStorage.
console.log(JSON.stringify(savedData, null, 2));
}
function getIndex(elem) {
return $(elem).parent('.parent').index();
}
$(document).on('click', '.removeMe', function() {
// Delete this from the saved Data
savedData.splice(getIndex(this), 1);
// And redisplay
refreshDisplay();
});
/* Swapping the displayed articles in the result list */
$(document).on('click', ".down-btn", function() {
var index = getIndex(this);
// Swap in memory
savedData.splice(index, 2, savedData[index+1], savedData[index]);
// And redisplay
refreshDisplay();
});
$(document).on('click', ".top-btn", function() {
var index = getIndex(this);
// Swap in memory
savedData.splice(index-1, 2, savedData[index], savedData[index-1]);
// And redisplay
refreshDisplay();
});
/* Disable top & down buttons for the first and the last article respectively in the result list */
function handleEvents() {
$(".top-btn, .down-btn").prop("disabled", false).show();
$(".parent:first").find(".top-btn").prop("disabled", true).hide();
$(".parent:last").find(".down-btn").prop("disabled", true).hide();
}
$(document).ready(function(){
$('#showExtForm-btn').click(function(){
$('#extUser').toggle();
});
$("#extUserForm").submit(function(e){
addExtUser();
return false;
});
});
function addExtUser() {
var extObj = {
name: {
title: "mr", // No ladies? :-)
first: $("#name").val(),
// Last name ?
},
dob: $("#dob").val(),
picture: {
thumbnail: $("#myImg").val()
},
location: { // maybe also ask for this info?
}
};
savedData.push(extObj);
refreshDisplay(); // Will show some undefined stuff (location...)
}
.parent {
background-color: #0000FF;
color: white;
border: 1px solid black;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#userList" onclick="userList(0)">User List</button>
<button class="btn btn-primary btn-sm" onclick="logSavedData()">Get Saved Data</button>
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#adminList" onclick="adminList(0)">User Admin</button>
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#extUser">Open External Form</button>
<div class="modal fade" id="userList" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">User List</h4>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-bordered table-hover" id="datatable">
<tr>
<th>Select</th>
<th>Name</th>
<th>DOB</th>
</tr>
</table>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary prev-btn"><span class="glyphicon glyphicon-chevron-left"></span></button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary next-btn"><span class="glyphicon glyphicon-chevron-right"></span></button>
</div>
</div>
<hr/>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary btn-sm" onclick="saveData()">Save selected</button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary btn-sm close-less-modal" data-dismiss="modal">Close</button>
</div>
</div>
<br />
</div>
</div>
</div>
</div>
<div class="modal fade" id="adminList" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Admin List</h4>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-bordered table-hover" id="datatable">
<tr>
<th>Select</th>
<th>Name</th>
<th>DOB</th>
</tr>
</table>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary prev-btn"><span class="glyphicon glyphicon-chevron-left"></span></button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary next-btn"><span class="glyphicon glyphicon-chevron-right"></span></button>
</div>
</div>
<hr/>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary btn-sm" onclick="saveData()">Save selected</button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary btn-sm close-less-modal" data-dismiss="modal">Close</button>
</div>
</div>
<br />
</div>
</div>
</div>
</div>
<div class="modal fade" id="extUser" role="dialog">
<div class="modal-dialog modal-lg">
<!-- External User-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Add External User</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id="extUserForm">
<div class="form-group">
<label class="control-label col-sm-3" for="name">Name:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="name" name="name" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="myImg">Image:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="myImg" name="myImg" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="dob">DOB:</label>
<div class="col-sm-8">
<input type="date" class="form-control" id="dob" name="dob" required>
</div>
</div>
<hr />
<div class="form-group">
<div class="col-sm-offset-3 col-sm-3">
<button class="btn btn-primary btn-sm">Submit</button>
</div>
<div class="col-sm-3">
<button type="reset" class="btn btn-primary btn-sm">Reset</button>
</div>
<div class="col-sm-3">
<button type="button" class="btn btn-primary btn-sm close-external-modal" data-dismiss="modal">Close</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="container"></div>
If you want the checkboxes to persist even when you move to another page, I would suggest that you actually keep those rows with checkboxes, but just hide them when moving to the next page.
The idea is that you never remove rows, but only add them when moving to a page you had not yet visited. But when going back to previous pages, you just make those 10 rows visible, and hide all others. That way you will even have a better user-experience, since those pages do not have to be requested from the server any more.
To achieve this, you just have to make a few changes in the first few lines of the creatTable function:
function createTable(resType, pageNo) {
// Update global variable
currentPageNo = pageNo;
// Set visibility of the correct "prev" button:
$('#' + resType + ' .prev-btn').toggle(pageNo > 0);
// *** See if we have that page already loaded
var $table = $('#' + resType + ' table');
// *** Count the rows already in the table, to see if we already have the page
var lastPageNo = $('tr:has(td)', $table).length - 1;
if (currentPageNo < lastPageNo) {
// *** We have the page: hide all rows, except those of that page
$('tr:has(td)', $table).hide().slice(currentPageNo, currentPageNo+10).show();
return;
}
// Otherwise make the request.
// Ask one record more than needed, to determine if there are more records after this page:
$.getJSON("https://api.randomuser.me/?results=11&resType="+resType + "&pageIndex=" + pageNo, function(data) {
//*** don't clear the table, but hide all rows, so they can be reused when paging back
$('tr:has(td)', $table).hide();
// Check if there's an extra record which we do not display,
// but determines that there is a next page
$('#' + resType + ' .next-btn').toggle(data.results.length > 10);
// ...etc ... etc
Here is the whole snippet:
var currentPageNo = 0; // Keep track of currently displayed page
// Select button that is descendant of userList
$('#userList .prev-btn').click(function(){
userList(currentPageNo-10);
});
$('#userList .next-btn').click(function(){
userList(currentPageNo+10);
});
$('#adminList .prev-btn').click(function(){
adminList(currentPageNo-10);
});
$('#adminList .next-btn').click(function(){
adminList(currentPageNo+10);
});
function userList(pageNo) {
var resType="userList";
createTable(resType,pageNo);
}
function adminList(pageNo) {
var resType="adminList";
createTable(resType,pageNo);
}
function createTable(resType, pageNo) {
// Update global variable
currentPageNo = pageNo;
// Set visibility of the correct "prev" button:
$('#' + resType + ' .prev-btn').toggle(pageNo > 0);
// *** See if we have that page already loaded
var $table = $('#' + resType + ' table');
// *** Count the rows already in the table, to see if we already have the page
var lastPageNo = $('tr:has(td)', $table).length - 1;
if (currentPageNo < lastPageNo) {
// *** We have the page: hide all rows, except those of that page
$('tr:has(td)', $table).hide().slice(currentPageNo, currentPageNo+10).show();
return;
}
// Otherwise make the request.
// Ask one record more than needed, to determine if there are more records after this page:
$.getJSON("https://api.randomuser.me/?results=11&resType="+resType + "&pageIndex=" + pageNo, function(data) {
//*** don't clear the table, but hide all rows, so they can be reused when paging back
$('tr:has(td)', $table).hide();
// Check if there's an extra record which we do not display,
// but determines that there is a next page
$('#' + resType + ' .next-btn').toggle(data.results.length > 10);
// Slice results, so 11th record is not included:
data.results.slice(0, 10).forEach(function (record, i) { // add second argument for numbering records
var json = JSON.stringify(record);
$table.append(
$('<tr>').append(
$('<td>').append(
$('<input>').attr('type', 'checkbox')
.addClass('selectRow')
.val(json),
(i+1+pageNo) // display row number
),
$('<td>').append(
$('<a>').attr('href', record.picture.thumbnail)
.addClass('imgurl')
.attr('target', '_blank')
.text(record.name.first)
),
$('<td>').append(record.dob)
)
);
});
}).fail(function(error) {
console.log("**********AJAX ERROR: " + error);
});
}
var savedData = []; // The objects as array, so to have an order.
function saveData(){
var errors = [];
// Add selected to map
$('input.selectRow:checked').each(function(count) {
// Get the JSON that is stored as value for the checkbox
var obj = JSON.parse($(this).val());
// See if this URL was already collected (that's easy with Set)
if (savedData.find(record => record.picture.thumbnail === obj.picture.thumbnail)) {
errors.push(obj.name.first);
} else {
// Append it
savedData.push(obj);
}
});
refreshDisplay();
if (errors.length) {
alert('The following were already selected:\n' + errors.join('\n'));
}
}
function refreshDisplay() {
$('.container').html('');
savedData.forEach(function (obj) {
// Reset container, and append collected data (use jQuery for appending)
$('.container').append(
$('<div>').addClass('parent').append(
$('<label>').addClass('dataLabel').text('Name: '),
obj.name.first + ' ' + obj.name.last,
$('<br>'), // line-break between name & pic
$('<img>').addClass('myLink').attr('src', obj.picture.thumbnail), $('<br>'),
$('<label>').addClass('dataLabel').text('Date of birth: '),
obj.dob, $('<br>'),
$('<label>').addClass('dataLabel').text('Address: '), $('<br>'),
obj.location.street, $('<br>'),
obj.location.city + ' ' + obj.location.postcode, $('<br>'),
obj.location.state, $('<br>'),
$('<button>').addClass('removeMe').text('Delete'),
$('<button>').addClass('top-btn').text('Swap with top'),
$('<button>').addClass('down-btn').text('Swap with down')
)
);
})
// Clear checkboxes:
$('.selectRow').prop('checked', false);
handleEvents();
}
function logSavedData(){
// Convert to JSON and log to console. You would instead post it
// to some URL, or save it to localStorage.
console.log(JSON.stringify(savedData, null, 2));
}
function getIndex(elem) {
return $(elem).parent('.parent').index();
}
$(document).on('click', '.removeMe', function() {
// Delete this from the saved Data
savedData.splice(getIndex(this), 1);
// And redisplay
refreshDisplay();
});
/* Swapping the displayed articles in the result list */
$(document).on('click', ".down-btn", function() {
var index = getIndex(this);
// Swap in memory
savedData.splice(index, 2, savedData[index+1], savedData[index]);
// And redisplay
refreshDisplay();
});
$(document).on('click', ".top-btn", function() {
var index = getIndex(this);
// Swap in memory
savedData.splice(index-1, 2, savedData[index], savedData[index-1]);
// And redisplay
refreshDisplay();
});
/* Disable top & down buttons for the first and the last article respectively in the result list */
function handleEvents() {
$(".top-btn, .down-btn").prop("disabled", false).show();
$(".parent:first").find(".top-btn").prop("disabled", true).hide();
$(".parent:last").find(".down-btn").prop("disabled", true).hide();
}
$(document).ready(function(){
$('#showExtForm-btn').click(function(){
$('#extUser').toggle();
});
$("#extUserForm").submit(function(e){
addExtUser();
return false;
});
});
function addExtUser() {
var extObj = {
name: {
title: "mr", // No ladies? :-)
first: $("#name").val(),
// Last name ?
},
dob: $("#dob").val(),
picture: {
thumbnail: $("#myImg").val()
},
location: { // maybe also ask for this info?
}
};
savedData.push(extObj);
refreshDisplay(); // Will show some undefined stuff (location...)
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#userList" onclick="userList(0)">User List</button>
<button class="btn btn-primary btn-sm" onclick="logSavedData()">Get Saved Data</button>
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#adminList" onclick="adminList(0)">User Admin</button>
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#extUser">Open External Form</button>
<div class="modal fade" id="userList" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">User List</h4>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-bordered table-hover" id="datatable">
<tr>
<th>Select</th>
<th>Name</th>
<th>DOB</th>
</tr>
</table>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary prev-btn"><span class="glyphicon glyphicon-chevron-left"></span></button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary next-btn"><span class="glyphicon glyphicon-chevron-right"></span></button>
</div>
</div>
<hr/>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary btn-sm" onclick="saveData()">Save selected</button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary btn-sm close-less-modal" data-dismiss="modal">Close</button>
</div>
</div>
<br />
</div>
</div>
</div>
</div>
<div class="modal fade" id="adminList" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Admin List</h4>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-bordered table-hover" id="datatable">
<tr>
<th>Select</th>
<th>Name</th>
<th>DOB</th>
</tr>
</table>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary prev-btn"><span class="glyphicon glyphicon-chevron-left"></span></button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary next-btn"><span class="glyphicon glyphicon-chevron-right"></span></button>
</div>
</div>
<hr/>
<div class="row">
<div class="col-sm-offset-3 col-sm-4">
<button type="button" class="btn btn-primary btn-sm" onclick="saveData()">Save selected</button>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-primary btn-sm close-less-modal" data-dismiss="modal">Close</button>
</div>
</div>
<br />
</div>
</div>
</div>
</div>
<div class="modal fade" id="extUser" role="dialog">
<div class="modal-dialog modal-lg">
<!-- External User-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Add External User</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id="extUserForm">
<div class="form-group">
<label class="control-label col-sm-3" for="name">Name:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="name" name="name" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="myImg">Image:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="myImg" name="myImg" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="dob">DOB:</label>
<div class="col-sm-8">
<input type="date" class="form-control" id="dob" name="dob" required>
</div>
</div>
<hr />
<div class="form-group">
<div class="col-sm-offset-3 col-sm-3">
<button class="btn btn-primary btn-sm">Submit</button>
</div>
<div class="col-sm-3">
<button type="reset" class="btn btn-primary btn-sm">Reset</button>
</div>
<div class="col-sm-3">
<button type="button" class="btn btn-primary btn-sm close-external-modal" data-dismiss="modal">Close</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="container"></div>

How to correctly implement in AngularJs: Custom directive reuse several times in single page

I created a custom directive that has event handler on it and use it 3 times.
<div sl-entity-browser btn_label="Browse supplier" handler="supplier_selection_handler(entity)" />
<div sl-entity-browser btn_label="Browse checker" handler="checker_selection_handler(entity)" />
<div sl-entity-browser btn_label="Browse approving officer" handler="approvar_selection_handler(entity)" />
In my controller:
$scope.supplier_selection_handler = function(entity){
$scope.selectedSupplier = entity;
}
$scope.checker_selection_handler = function(entity){
$scope.selectedChecker = entity;
}
$scope.approvar_selection_handler = function(entity){
$scope.selectedApprovingOfficer = entity;
}
My directive:
return {
scope : {
btnLabel : '#',
handler: '&'
},
restrict: 'AE',
templateUrl: '/common/sl-entity-browser',
link: function (scope, elem, attrs) {
// expose selected account to the outside world
scope.selectEntity = function(entity) {
return $timeout(function() {
return scope.handler({
entity: entity
});
});
}
}
};
HTML template:
<button title="browse account" class="btn btn-primary" data-toggle="modal" data-target="#slEntityModal"> {{ btnLabel }}</button>
<div class="modal fade" id="slEntityModal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" style="width: 90%">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Browse entities</h4>
</div>
<div class="modal-body">
<div>
<div class="row">
<div class="input-group pull-right" style="width: 300px">
<input class="form-control" placeholder="Search" ng-model="query" />
<span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12">
<div class="row-top-buffer" style="margin-top: 15px"/>
<div class='row' style="border-top: 1px solid #dcdcdc; padding-top: 10px">
<div class="col-md-1 col-lg-1"><span style="font-weight: bold; padding-left: 2px;">Acct No</span></div>
<div class="col-md-5 col-lg-5"><span style="font-weight: bold; padding-left: 30px;">Name</span></div>
<div class="col-md-6 col-lg-6"><span style="font-weight: bold">Address</span></div>
</div>
<div class="row-top-buffer" style="margin-top: 5px"/>
<div class="row" style='max-height: 500px; overflow: auto;'>
<div ng-show="!slEntities">Loading entities...</div>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
</tr>
</thead>
<tbody>
<tr data-dismiss="modal" ng-repeat="entity in entities = (slEntities | filter:query)" style="cursor: pointer" ng-click="selectEntity(entity)">
<td style="width: 100px;">{{entity.accountNo}}</td>
<td style="width: 480px;">{{entity.name}} <span class="label {{entityClass(entity.marker)}} pull-right">{{convert(entity.marker)}}</span></td>
<td>{{entity.address}}</td>
</tr>
<tr ng-show="entities.length == 0"><td colspan="3" align="center">No records found</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The directive will render a button that will display a modal when clicked. The modal contains a table of items. If a certain item is selected, the modal will be disposed and the event should trigger the correct one as defined. The problem is that the first directive instance' event handler (supplier_selection_handler) is always called.
I am new to AngularsJs.
Thanks in advance.
This is because the modal opened by your directives (all of them!) is the first directive's modal. Notice that all your modals share the same ID? and the data-target of your buttons share the same ID? Since an ID of an element is unique, then once an element with that specific ID is found, it'll stop searching for another element with such ID. Thus, all your buttons that opens a modal simply opens the first modal.
I recommend that you use angular-bootstrap's modal instead, the component itself runs in the AngularJS context so no scoping problems may occur.
The example below shows how to create a directive that can makes use of angular-bootstrap's modal, I trimmed down the code below to simplify the demo.
DEMO
INDEX
<body ng-controller="Ctrl">
<button sl-entity-browser
btn-label="hello world"
handler="messageHandler('This is a message from hello world')"
class="btn btn-primary">
Hello World?
</button>
<button sl-entity-browser
btn-label="Yeah Baby"
handler="messageHandler('WEEEE wOoOoOw')"
class="btn btn-primary">
Baby?
</button>
<button sl-entity-browser
btn-label="Boom!"
handler="messageHandler('This is kaboom boom!')"
class="btn btn-primary">Kaboom!</button>
</body>
MODAL
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
{{ btnLabel }}
</div>
<div class="modal-footer">
<button
ng-click="handler()"
class="btn btn-primary pull-left">
Click ME!
</button>
</div>
JAVASCRIPT
(function(angular) {
var app = angular.module('app', ['ui.bootstrap']);
app.controller('Ctrl', function($scope, $window) {
// handler function
$scope.messageHandler = function(message) {
$window.alert(message);
};
});
// directive assignment
app.directive('slEntityBrowser', slEntityBrowser);
function slEntityBrowser() {
// directive definition
return {
scope: {
btnLabel: '#',
handler: '&'
},
controller: slEntityBrowserController,
link: slEntityBrowserLink
};
}
// directive controller
function slEntityBrowserController($scope, $modal) {
// create open() method
// to open a modal
$scope.open = function() {
$modal.open({
scope: $scope,
templateUrl: 'sl-entity-browser-modal.html'
});
};
}
// directive link
function slEntityBrowserLink(scope, elem) {
// register click handler on the current element
// to open the modal
elem.on('click', function() {
scope.open();
});
}
})(window.angular);

Angular CRUD delete row from modal

I am using a simple CRUD API in MEAN STACK with a delete function
app.delete('/api/users/:user_id', function(req, res) {
users.remove({
_id : req.params.user_id
}, function(err, user) {
if (err)
res.send(err);
users.find(function(err, users) {
if (err)
res.send(err)
res.json(users);
});
});
});
The controller
var app = angular.module('usersList', []);
app.controller('usersController', function($scope, $http) {
$http.get('/api/users')
.success(function(userData) {
$scope.users = userData;
$scope.length = userData.length;
})
.error(function(data) {
console.log('Error: ' + data);
});
$scope.deleteUser = function(id) {
$http.delete('/api/users/' + id)
.success(function(data) {
$scope.users = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
});
In the HTML file I populate a table as follow with a btn to open modal with corresponding user details by getting the {{$index}}
<body data-ng-controller="usersController">
<table>
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th>Login</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="userData in users" >
<td><input type="checkbox"/></td>
<td>{{ userData._id }}</td>
<td>{{ userData.id_userLogin }}</td>
<td>{{ userData.email }}</td>
<td>
<!-- Button trigger for Delete modal -->
<button type="button" data-toggle="modal" data-target="#deleteModal{{$index}}" data-ng-click="Clear()">
<span class="glyphicon glyphicon-trash"></span>
</button>
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal{{$index}}" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Delete <strong>{{ userData.id_userLogin }}</strong> account</h4>
</div>
<div class="modal-body">
<div class="alert alert-danger" role="alert">Are you sure you want to delete this account?</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-danger" data-ng-click="deleteUser(user._id)">Delete</button>
</div>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
How can I use the API to delete the corresponding user from the modal as following does not work
<button type="button" class="btn btn-danger" data-ng-click="deleteUser(user._id)">Delete</button>
It is important that the modal is not a confirm delete popup but a modal with content from where the delete button will delete the corresponding user. Any help would be appreciated.
Seem like the problem is solved. I'll just post the answer here. The html of the button should be:
<button type="button" class="btn btn-danger" data-ng-click="deleteUser(userData._id)">Delete</button>
<!-- Use userData._id instead of user._id-->

Opening a DIV in the HTML as Modal in AngularJS

Learning some AngularJS here...
I have an Angular application which connects to an ASP.Net WebAPI.
I am trying to have a DIV inside my HTML open as a modal window.
My HTML looks as follows:
<div class="container" style="padding-top:20px;">
<div ng-app="vehicleApp" data-ng-controller="testingController" class="container">
<div ng-show="error" class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<p>{{ error }}</p>
</div>
<div class="modal fade" id="vehicleModel" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">X</button>
<h4 class="modal-title" id="myModalLabel" ng-hide="editMode">Add vehicle</h4>
<h4 class="modal-title" id="myModalLabel" ng-show="editMode">Edit vehicle: {{ vehicle.Id }}</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" role="form" name="addvehicleform">
<div class="form-group">
<label for="title" class="col-sm-3 control-label">vehicle Name</label>
<div class="col-sm-7">
<input type="text" data-ng-model="vehicle.Name" class="form-control" id="vehiclename" placeholder="vehicle Name" required title="Enter your vehicle Name" />
</div>
</div>
<div class="form-group">
<label for="title" class="col-sm-3 control-label">Identification Account</label>
<div class="col-sm-7">
<input type="number" data-ng-model="vehicle.vehicleIdentificationAccountId" class="form-control" id="vehicleIdentificationAccountId" placeholder="vehicle Identification Account" required title="Enter your Identification Account" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-7">
<span data-ng-hide="editMode">
<input type="submit" value="Add" ng-disabled="addvehicleform.$invalid" data-ng-click="add()" class="btn btn-primary normal-button" />
</span>
<span data-ng-show="editMode">
<input type="submit" value="Update" ng-disabled="addvehicleform.$invalid" data-ng-click="update()" class="btn btn-primary normal-button" />
</span>
<input type="button" value="Cancel" data-ng-click="cancel()" class="btn btn-primary" />
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<h1>Vehicle List</h1>
<p><a data-ng-click="showadd()" href="javascript:;" class="btn btn-primary">Add New vehicle</a></p>
<table class="table table-striped table-bordered table-hover table-condensed">
<thead>
<tr>
<th>Vehicle ID</th>
<th>Name</th>
<th>Identification Account</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr data-ng-hide="agencies || agencies.length > 0">
<td colspan="4">
<div class="text-center text-warning">
<strong>No Agencies Retrieved</strong>
</div>
</td>
</tr>
<tr data-ng-repeat="vehicle in agencies">
<td>{{vehicle.Id}}</td>
<td>{{vehicle.Name}}</td>
<td>{{vehicle.vehicleIdentificationAccountId}}</td>
<td>
<a data-ng-click="get(vehicle)" href=""><span class="glyphicon glyphicon-open"></span>View</a>
<a data-ng-click="edit(vehicle)" href=""><span class="glyphicon glyphicon-edit"></span>Edit</a>
<a data-ng-click="showConfirm(vehicle)" href=""><span class="glyphicon glyphicon-remove-circle"></span>Delete</a>
</td>
</tr>
</tbody>
</table>
<hr />
<div class="modal fade" id="viewModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">X</button>
<h4 class="modal-title" id="myModalLabel">View vehicle Detail</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" role="form" name="viewuser">
<div class="form-group">
<label for="ID" class="col-sm-3 control-label">ID</label>
<div class="col-sm-7">
{{vehicle.Id}}
</div>
</div>
<div class="form-group">
<label for="Name" class="col-sm-3 control-label">Name</label>
<div class="col-sm-7">
{{vehicle.Name}}
</div>
</div>
<div class="form-group">
<label for="vehicleIdentificationAccountId" class="col-sm-3 control-label">Identification Account</label>
<div class="col-sm-7">
{{vehicle.vehicleIdentificationAccountId}}
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="confirmModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">X</button>
<h4 class="modal-title" id="myModalLabel">Confirm</h4>
</div>
<div class="modal-body">
Are you sure you want to delete vehicle: {{ vehicle.Name}}?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" data-ng-click="delete()" style="width:100px;">Ok</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" style="width:100px;">Cancel</button>
</div>
</div>
</div>
</div>
</div>
</div>
testingController.js
'use strict';
app.controller('testingController', function ($scope, testingDataService, $modal) {
$scope.vehicles = [];
$scope.vehicle = null;
$scope.editMode = false;
// Get vehicle
$scope.get = function () {
$scope.vehicle = this.vehicle;
$('#viewModal').modal('show');
};
//get all vehicles
$scope.getAll = function () {
testingDataService.getvehicleList().success(function (data) {
$scope.vehicles = data;
}).error(function (data) {
$scope.error = "An Error has occured while Loading vehicles! " + data.ExceptionMessage;
});
};
// add vehicle
$scope.add = function () {
var currentvehicle = this.vehicle;
if (currentvehicle != null && currentvehicle.Name != null && currentvehicle.vehicleIdentificationAccountId!= null) {
testingDataService.addvehicle(currentvehicle).success(function (data) {
$scope.addMode = false;
currentvehicle = data;
$scope.vehicles.push(currentvehicle);
//reset form
$scope.vehicle = null;
$('#vehicleModel').modal('hide');
}).error(function (data) {
$scope.error = "An Error has occured while Adding vehicle! " + data.ExceptionMessage;
});
}
};
//edit vehicle
$scope.edit = function () {
$scope.vehicle = this.vehicle;
$scope.editMode = true;
$('#vehicleModel').modal('show');
};
//update vehicle
$scope.update = function () {
var currentvehicle = this.vehicle;
testingDataService.updatevehicle(currentvehicle).success(function (data) {
currentvehicle.editMode = false;
$('#vehicleModel').modal('hide');
}).error(function (data) {
$scope.error = "An Error has occured while Updating vehicle! " + data.ExceptionMessage;
});
};
// delete
$scope.delete = function () {
currentvehicle = $scope.vehicle;
testingDataService.deletevehicle(currentvehicle).success(function (data) {
$('#confirmModal').modal('hide');
$scope.vehicles.pop(currentvehicle);
}).error(function (data) {
$scope.error = "An Error has occured while Deleting vehicle! " + data.ExceptionMessage;
$('#confirmModal').modal('hide');
});
};
//Modal popup events
$scope.showadd = function () {
$scope.vehicle = null;
$scope.editMode = false;
$('#vehicleModel').modal({ backdrop: 'static' });
$('#vehicleModel').modal('show');
};
$scope.showedit = function () {
$('#vehicleModel').modal({ backdrop: 'static' });
$('#vehicleModel').modal('show');
};
$scope.showConfirm = function (data) {
$scope.vehicle = data;
$('#confirmModal').modal('show');
};
$scope.cancel = function () {
$scope.vehicle = null;
$('#vehicleModel').modal('hide');
}
// initialize your users data
$scope.getAll();
});
Basically when I click on the Add New Vehicle button, the console says:
ReferenceError: $ is not defined
on the line in the controller where it is supposed to show the modal:
$('#vehicleModel').modal({ backdrop: 'static' });
I am a bit lost on how to resolve this.
Appreciate any insight.
P.S. The data loads fine when this HTML view is loaded up. I also added a console.log inside the
$scope.showadd = function (){
console.log('Test');
};
and that is logged properly in the console. So totally lost right now...
Update:
Did a little more investigation. I issued in Chrome console the command:
$('#vehicleModel')
and it showed me the div with the id=vehicleModel.
I would argue that you should probably be using Angular UI Bootstrap to create your modal dialogs. Here is the link.
Here is a cut down version of how to open a modal using Angular UI Bootrstrap:
$scope.open = function (vehicle) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
resolve: {
items: function () {
return $scope.items;
}
}
});
};
MODAL CONTENT
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">Modal!</h3>
</div>
<div class="modal-body">
<div >Body</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="$close('awesome')">OK</button>
<button class="btn btn-warning" ng-click="$dismiss('nah')">Cancel</button>
</div>
</script>
HTML
<a data-ng-click="open(vehicle)" href=""><span class="glyphicon glyphicon-open"></span>View</a>
You're trying to grab your element the jQuery way. $ is reserved in Angular. try using:
angular.element('div').modal({ backdrop: 'static' });
where 'div' is whatever your actual tag name is, and traverse the DOM for it...
EDIT: from https://docs.angularjs.org/error/jqLite/nosel
In order to resolve this error, rewrite your code to only use tag name selectors and manually traverse the DOM using the APIs provided by jqLite.
Alternatively, you can include a full version of jQuery, which Angular
will automatically use and that will make all selectors available.
You can code like this:
// Pre-fetch an external template populated with a custom scope
var myOtherModal = $modal({scope: $scope, template: 'modal/docs/modal.demo.tpl.html', show: false});
// Show when some event occurs (use $promise property to ensure the template has been loaded)
$scope.showModal = function() {
myOtherModal.$promise.then(myOtherModal.show);
};

Resources