check duplicates from the list and show error messge - javascript

Plunkr
From the above example, Created a list and the list will be in editable mode on click edit button.
It is created using angular-xeditable.
From the list, just want to check the duplicates and show an error message if it matches.
The below code able to find the duplicates and shows an error. But, if the two or more values has the same name. the following error happens.
If the changes has done in any of them then other value of the error
messages remain the same.
The error messages is not hiding on click the delete button (x).
Thanks in advance.
scripts.js
var app = angular.module('app', ['ngRoute', 'xeditable']);
app.controller('indexController', ['$scope', '$http', function ($scope, $http) {
$scope.showIcons = false;
$scope.newVal = "";
$scope.noPossValues = false;
$scope.getParamInfo = function (id) {
if (id !== undefined) {
$http.get('./getparameterbyid.json').success(function (data) {
if (data.param_values.length == 0)
$scope.noPossValues = true;
$scope.paraInfo = data;
}).error(function (err) {
console.log("Err : ", err);
});
}
};
$scope.addNewValue = function (val, id) {
$scope.paraInfo.param_values.push({
value: $scope.newVal,
default_value: null,
operation: null
});
$scope.newVal = "";
$scope.noPossValues = false;
};
$scope.updatedPossValue = function (val, index) {
var values = [];
input = val.toLowerCase();
$scope.paraInfo.param_values.map(function (item, i) {
if (val == "" && index == i) {
item.error_msg = true;
}
if (val != "" && index == i) {
item.error_msg = false;
}
if (item.operation == null)
values.push(item.value.toLowerCase());
if (index == i) {
item.value = val;
}
});
if (values.indexOf(input) > -1) {
$scope.paraInfo.param_values.map(function (item, i) {
if (item.operation == null) {
if (item.value.toLowerCase() == input) {
item.dup_item = true;
} else {
item.dup_item = false;
}
}
})
} else {
$scope.paraInfo.param_values[index].dup_item = false;
}
};
$scope.removePossVal = function (id) {
var deleteCount = 0,
nullCount = 0;
var indexOfItem = $scope.paraInfo.param_values.indexOf($scope.paraInfo.param_values[id]);
$scope.paraInfo.param_values[indexOfItem].operation = "delete";
$scope.paraInfo.param_values.map(function (item, index) {
if (item.error_msg != undefined && index == id)
delete item.error_msg;
if (item.operation == null)
nullCount += 1;
if (item.operation == "delete")
deleteCount += 1;
});
if (deleteCount == $scope.paraInfo.param_values.length) {
$scope.showIcons = true;
$scope.noPossValues = true;
}
};
$scope.enableEdit = function (action) {
if (action != 'cancel' || action != 'submit')
$scope.showIcons = !$scope.showIcons;
};
$scope.submitParameter = function () {
$scope.enableEdit();
};
$scope.editableParameter = function () {
$scope.tableform.$show();
$scope.enableEdit();
};
$scope.cancelParameter = function () {
if ($scope.showIcons == true)
$scope.enableEdit('cancel');
};
}]);
index.html
<!DOCTYPE html>
<html>
<head>
<!-- Stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="http://vitalets.github.io/angular-xeditable/starter/angular-xeditable/css/xeditable.css" rel="stylesheet">
<!-- scripts-->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular-route.min.js">
</script>
<script src="http://vitalets.github.io/angular-xeditable/starter/angular-xeditable/js/xeditable.js">
</script>
<script src="script.js">
</script>
</head>
<body ng-app="app" ng-controller="indexController">
<div class="container mt-5">
<form action="" editable-form name="tableform" onaftersave="submitParameter()" oncancel="cancelParameter()">
<div ng-init="getParamInfo('10')">
<button type="button" class="btn btn-primary pull-right cur-point mb-3" ng-show="!tableform.$visible"
ng-click="editableParameter()">
<i class="fa fa-pencil"></i> Edit Fields
</button>
<div class="form-group row text-center">
<label for="colFormLabel" class="col-sm-5 m-1 col-form-label">Possible Values : </label>
<div class="col-sm-6">
<div style="display: flex;">
<div class="card" style="width: 70%; min-height: 2.5rem; margin: 0 auto;" ng-hide="noPossValues">
<ul class="list-group list-group-flush" ng-repeat="(index, pv) in paraInfo.param_values">
<li style="padding: 0.44rem;" class="list-group-item" ng-show="!showIcons && pv.value != undefined && pv.operation != 'delete'">{{pv.value}}</li>
<div class="input-group" ng-show="showIcons && pv.value != undefined && pv.operation != 'delete'">
<input type="text" class="form-control rounded-0" ng-class="updateVal == '' ? 'has-error no-border-color' : ''"
ng-value="pv.value" ng-model="updateVal" ng-change="updatedPossValue(updateVal, index)">
<span class="input-group-btn" style="border-bottom: 2px solid rgba(0,0,0,.15);"
ng-class="updateVal == '' ? 'has-error' : ''">
<a class="btn btn-danger rounded-0 cur-pointer text-white" ng-click="removePossVal(index)">
<i class="fa fa-remove"></i>
</a>
</span>
</div>
<span class="text-danger text-left" ng-show="pv.error_msg">No empty values</span>
<span class="text-danger param-poss-values" ng-show="pv.dup_item">No duplicate values</span>
</ul>
</div>
<div ng-show="noPossValues && showIcons" class="d-flex">
<input type="text" class="form-control add-new-inp-txt" ng-model="newVal" placeholder="Add new...">
<button class="btn btn-info cur-pointer text-white add-new-btn" ng-click="addNewValue(newVal)"
ng-disabled="newVal == ''">
<i class="fa fa-plus"></i>
</button>
</div>
</div>
</div>
</div>
<div class="form-group row" ng-show="showIcons && paraInfo.param_values.length > 0 && !noPossValues">
<label for="colFormLabel" class="col-sm-5 m-1 col-form-label : "></label>
<div class="col-sm-6 text-center">
<div style="display: flex; width: 70%; margin-left: 15%;">
<input type="text" name="pincode" ng-pattern="patternValueBox" class="form-control add-new-inp-txt"
ng-model="newVal" ng-change="checkDuplicateValue(newVal)" placeholder="Add new...">
<button class="btn btn-info cur-pointer text-white add-new-btn" ng-click="addNewValue(newVal)"
ng-disabled="newVal == '' || duplicateValue">
<i class="fa fa-plus"></i>
</button>
<span class="text-danger param-poss-values" ng-show="duplicateValue">No duplicate
values</span>
</div>
</div>
</div>
<div class="text-center mt-5 row" ng-show="tableform.$visible">
<div class="col-md-4">
<button type="button" ng-disabled="tableform.$waiting" ng-click="tableform.$cancel()" class="btn btn-outline-secondary mr-3 cur-point">Cancel</button>
</div>
<div class="col-md-4">
<button type="submit" class="col-sm-7 btn btn-outline-success mr-3 ml-3 cur-point" ng-disabled="updateVal == ''">Submit{{updateVal}}</button>
</div>
</div>
</div>
</form>
</div>
</body>
</html>

def FindDuplicates(in_list):
unique = set(in_list)
for each in unique:
count = in_list.count(each)
if count > 1:
print 'There are duplicates in this list'
return True
print 'There are no duplicates in this list'
return False
if name == 'main':
# test it
a = [8, 64, 16, 32, 4, 24]
b = [2,2,3,6,78,65,4,4,5]
FindDuplicates(a)
FindDuplicates(b)

Related

How do I disable the submit button until all fields are complete in a bootstrap modal?

How do I check if the input fields are filled up before I enable the submit button in the modal?
I'm also trying to figure out how I can call my function once I open my button. I tried calling a function on click but it won't work.
I'm not sure how to implement a function to check the input fields and how to call the function when the modal is opened
function checkModal() {}
function validate() {
if ($('#id').val() &&
$('#fname').val() &&
$('#lname').val() &&
$('#sub1').val() &&
$('#sub2').val() &&
$('#sub3').val() &&
$('#sub4').val() &&
$('#sub5').val() &&
$('#grade1').val() &&
$('#grade2').val() &&
$('#grade3').val() &&
$('#grade4').val() &&
$('#grade5').val().length > 0) {
// disable bootstrap button
}
}
$(document).ready(function() {
validate();
$('#id, #lname, #fname, #sub1, #sub2, #sub3, #sub4, #sub5, #grade1, #grade2, #grade3, #grade4, #grade5').change(validate);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" ></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" />
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title" id="exampleModalLabel">New Student Form</h2>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<h6>ID</h6>
<input type="text" id="id">
<h6>Lastname</h6>
<input type="text" id="lname">
<h6>Firstname</h6>
<input type="text" id="fname">
<h6>Course</h6>
<select name="courses" id="courses">
<option value="BS Information Technology">BS Information Technology</option>
<option value="BS Information Systems">BS Information Systems</option>
<option value="BS Computer Scicence">BS Computer Scicence</option>
<option value="BS Data Science">BS Data Science</option>
</select>
<hr>
<div class="container1">
<h6>Subject 1</h6>
<input type="text" id="sub1" required>
<h6>Subject 2</h6>
<input type="text" id="sub2" required>
<h6>Subject 3</h6>
<input type="text" id="sub3">
<h6>Subject 4</h6>
<input type="text" id="sub4">
<h6>Subject 5</h6>
<input type="text" id="sub5">
</div>
<div class="container2">
<h6>Grade</h6>
<input type="text" id="grade1">
<h6>Grade</h6>
<input type="text" id="grade2">
<h6>Grade</h6>
<input type="text" id="grade3">
<h6>Grade</h6>
<input type="text" id="grade4">
<h6>Grade</h6>
<input type="text" id="grade5">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" aria-disabled="true" onclick="checkModal()" id="add_student">Save changes</button>
</div>
</div>
</div>
</div>
</div>
You can find all empty and disable if any found
const empty = $('.modal-body :input')
.filter(function() {
return this.value.trim() === ""
}).length>0;
$('#add_student').prop('disabled',empty);
Perhaps from the start:
$(function() {
const $inputs = $('.modal-body :input');
const $addStudent = $('#add_student');
$inputs.on('change',function() {
const empty = $inputs
.filter(function() { return this.value.trim() === "" })
.length>0;
$addStudent.prop('disabled',empty);
});
})
for the disabled, you can use prop("disabled", true); to your button. Try the below code.
if (
$('#id').val() == '' ||
$('#fname').val() == '' ||
$('#lname').val() == '' ||
$('#sub1').val() == '' ||
$('#sub2').val() == '' ||
$('#sub3').val() == '' ||
$('#sub4').val() == '' ||
$('#sub5').val() == '' ||
$('#grade1').val() == '' ||
$('#grade2').val() == '' ||
$('#grade3').val() == '' ||
$('#grade4').val() == '' ||
$('#grade5').val() == ''
){
$('#add_student').prop("disabled",true);
}
Give all of your inputs a common class like modal__inputs
// Select all inputs
const all_inputs = document.querySelectorAll(".modal__inputs");
// Set disabled variable false
let disabled = false;
// Map through all the inputs,
//if any input is empty the disabled variable will be set to true
for(let i=0;i<all_inputs.length;i++){
if(all_inputs[i].value.trim() === ""){
disabled = true;
break;
}
}
// Set button disabled
const button = document.getElementById("add_button");
button.disabled = disabled;

PHP laravel and JQuery AJAX append form input

Hey guys I am just wondering how I can append a view within Laravel to my page using AJAX.
How can I append just input nema="result" and insert data into the database with laravel.
Error: [HTTP/1.1 422 Unprocessable Entity 323ms]
My blad file
<form id="repeater_form" class="row" action="{{route('agreement.store')}}" method="post" enctype="multipart/form-data">
#csrf
<div class="col-sm-3 form-group">
<label>Year</label>
<select class="form-control select2" name="year" >
<option value="">--select--</option>
#foreach ($years as $key => $value)
<option value="{{ $key }}">{{ $value }}</option>
#endforeach
</select>
</div>
<div class="form-group">
<label>target</label>
<input type="text" name="target" id="target" class="form-control" />
</div>
<div id="repeater">
<div class="repeater-heading" align="right">
<button type="button" class="btn btn-primary repeater-add-btn">Add More Skill</button>
</div>
<div class="clearfix"></div>
<div class="items" data-group="programming_languages">
<div class="item-content">
<div class="form-group">
<div class="row">
<input type="text" name="result[]" id="result" class="form-control" required />
<div class="col-md-3" style="margin-top:24px;" align="center">
<button id="remove-btn" class="btn btn-danger" onclick="$(this).parents('.items').remove()">Remove</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-12 form-group">
<button name="insert" type="submit" class="btn btn-primary"><i class="fa fa-save"></i> Submit</button>
backe
</div>
</form>
Js File
<script>
$(document).ready(function(){
$("#repeater").createRepeater();
$('#repeater_form').on('submit', function(event){
event.preventDefault();
$.ajax({
url: '{{route('agreement.store')}}',
method:"POST",
data:$(this).serialize(),
success:function(data)
{
$('#repeater_form')[0].reset();
$("#repeater").createRepeater();
$('#success_result').html(data);
}
});
});
});
</script>
I am new in laravel Here what am I doing I am going to insert a simple form value into database. Now, what happen when I click on submit button it is not insert data. I have no idea about that. So, How can I do this? Please help me.
Thank You.
My Contoroller
public function store(CreateAgreement $request)
{
$agreements = new Agreement;
$agreements->target = $request->target;
$agreements->result = $request->result;
$agreements->years()->attach(request('year'));
$agreements->save();
return redirect()->route('agreement.index');
}
CreateAgreement Request
public function rules()
{
return [
'year' => ['required'],
'code' => ['required'],
'target' => ['required'],
'result' => ['required'],
];
}
Repeater js
jQuery.fn.extend({
createRepeater: function () {
var addItem = function (items, key) {
var itemContent = items;
var group = itemContent.data("group");
var item = itemContent;
var input = item.find('input,select');
input.each(function (index, el) {
var attrName = $(el).data('name');
var skipName = $(el).data('skip-name');
if (skipName != true) {
$(el).attr("name", group + "[" + key + "]" + attrName);
} else {
if (attrName != 'undefined') {
$(el).attr("name", attrName);
}
}
})
var itemClone = items;
/* Handling remove btn */
var removeButton = itemClone.find('.remove-btn');
if (key == 0) {
removeButton.attr('disabled', true);
} else {
removeButton.attr('disabled', false);
}
$("<div class='items'>" + itemClone.html() + "<div/>").appendTo(repeater);
};
/* find elements */
var repeater = this;
var items = repeater.find(".items");
var key = 0;
var addButton = repeater.find('.repeater-add-btn');
var newItem = items;
if (key == 0) {
items.remove();
addItem(newItem, key);
}
/* handle click and add items */
addButton.on("click", function () {
key++;
addItem(newItem, key);
});
}
});

Sharing data between different controllers

I want to build a small application (for learning Angular JS) that can define a list of locations and a list of events. The application was developed based on the tutorial found here: http://g00glen00b.be/prototyping-spring-boot-angularjs/.
When defining a new event I would like to associate a location for the new event. The location should be selected using a combobox.
So first I define 2 locations, let's say Location 1 and Location 2. I want to bind somehow the list of available locations (1 and 2) to the combobox labeled "Location select" see this image
So far I was able to bind the location list to the combobox, but the items of the combobox are updated only when I refresh the browser. I would like to be able to automatically refresh the content of the combobox whenever the list of available locations is changed (a new location is added or a location is removed).
Here is my HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet"
href="./bower_components/bootstrap-css-only/css/bootstrap.min.css" />
</head>
<body ng-app="myEventApp">
<div class="container" ng-controller="EventAppController" >
<div class="page-header">
<h1>Edit Events</h1>
</div>
<div class="alert alert-info" role="alert"
ng-hide="events && events.length > 0">There are no events yet.
</div>
<form class="form-horizontal" role="form"
ng-submit="addEvent(newEventName,newEventDescription)" ng-controller="LocationAppController">
<div >Locations: {{locations}}</div>
<div class="form-group" ng-repeat="event in events">
<div class="checkbox col-xs-9">
<label> <strong>{{event.name}}</strong> /
{{event.description}}
</label>
</div>
<div class="col-xs-3">
<button class="pull-right btn btn-danger" type="button"
title="Delete" ng-click="deleteEvent(event)">
<span class="glyphicon glyphicon-trash"></span>
</button>
</div>
</div>
<hr />
<div class="input-group">
<input type="text" class="form-control" ng-model="newEventName"
placeholder="Enter the name..." /> <input type="text"
class="form-control" ng-model="newEventDescription"
placeholder="Enter the description..." />
<label for="locationSelect">Location select: </label>
<select
name="locationSelect" id="locationSelect" ng-model="data.repeatSelect">
<option value="">---Please select---</option>
<option ng-repeat="location in locations"
value="{{location.id}}">{{location.name}}</option>
</select>
<div class="col-md-6"></div>
<span class="input-group-btn">
<button class="btn btn-default" type="submit"
ng-disabled="!newEventName||!newEventDescription" title="Add">
<span class="glyphicon glyphicon-plus"></span>
</button>
</span>
</div>
</form>
</div>
<!-- Location -->
<div class="container" ng-controller="LocationAppController">
<div class="page-header">
<h1>Edit Locations</h1>
</div>
<div class="alert alert-info" role="alert"
ng-hide="locations && locations.length > 0">There are no
locations defined yet.</div>
<form class="form-horizontal" role="form"
ng-submit="addLocation(newLocationName,newLocationAddress)">
<div class="form-group" ng-repeat="location in locations">
<div class="checkbox col-xs-9">
<label> <strong>{{location.name}}</strong> /
{{location.address}}
</label>
</div>
<div class="col-xs-3">
<button class="pull-right btn btn-danger" type="button"
title="Delete" ng-click="deleteLocation(location)">
<span class="glyphicon glyphicon-trash"></span>
</button>
</div>
</div>
<hr />
<div class="input-group">
<input type="text" class="form-control" ng-model="newLocationName"
placeholder="Enter the name..." /> <input type="text"
class="form-control" ng-model="newLocationAddress"
placeholder="Enter the address..." />
<!-- <label>Location: </label> -->
<!-- <select -->
<!-- name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect"> -->
<!-- <option ng-repeat="option in data.availableOptions" -->
<!-- value="{{option.id}}">{{option.name}}</option> -->
<!-- </select> -->
<div class="col-md-6"></div>
<span class="input-group-btn">
<button class="btn btn-default" type="submit"
ng-disabled="!newLocationName||!newLocationAddress" title="Add">
<span class="glyphicon glyphicon-plus"></span>
</button>
</span>
</div>
</form>
</div>
<script type="text/javascript"
src="./bower_components/angular/angular.min.js"></script>
<script type="text/javascript"
src="./bower_components/angular-resource/angular-resource.min.js"></script>
<script type="text/javascript"
src="./bower_components/lodash/dist/lodash.min.js"></script>
<script type="text/javascript" src="./app/eventApp.js"></script>
<script type="text/javascript" src="./app/eventControllers.js"></script>
<script type="text/javascript" src="./app/eventServices.js"></script>
<script type="text/javascript" src="./app/locationControllers.js"></script>
<script type="text/javascript" src="./app/locationServices.js"></script>
<script type="text/css" src="./app/custom.css"></script>
</body>
</html>
And these are the controllers used:
eventControllers.js
(function(angular) {
var EventAppController = function($scope, Event) {
Event.query(function(response) {
$scope.events = response ? response : [];
});
$scope.addEvent = function(name, description) {
new Event({
locations:[],
name : name,
description : description,
}).$save(function(event) {
$scope.events.push(event);
});
$scope.newEventName = "";
$scope.newEventDescription = "";
};
$scope.updateEvent = function(event) {
event.$update();
};
$scope.deleteEvent = function(event) {
event.$remove(function() {
$scope.events.splice($scope.events.indexOf(event), 1);
});
};
};
EventAppController.$inject = [ '$scope', 'Event' ];
angular.module("myEventApp.controllers").controller("EventAppController",
EventAppController);
}(angular));
locationControllers.js
(function(angular) {
var LocationAppController = function($scope, Location) {
Location.query(function(response) {
$scope.locations = response ? response : [];
});
$scope.addLocation = function(name, address) {
new Location({
name: name,
address: address,
}).$save(function(location) {
$scope.locations.push(location);
});
$scope.newLocationName = "";
$scope.newLocationAddress = "";
};
$scope.updateLocation = function(location) {
location.$update();
};
$scope.deleteLocation = function(location) {
location.$remove(function() {
$scope.locations.splice($scope.locations.indexOf(location), 1);
});
};
return {
getLocations: function() {
return $scope.locations;
}
}
};
LocationAppController.$inject = ['$scope', 'Location'];
angular.module("myEventApp.controllers").controller("LocationAppController", LocationAppController);
}(angular));
eventServices.js
(function(angular) {
var EventFactory = function($resource) {
return $resource('/event/:id', {
id : '#id'
}, {
update : {
method : "PUT"
},
remove : {
method : "DELETE"
}
});
};
EventFactory.$inject = [ '$resource' ];
angular.module("myEventApp.services").factory("Event", EventFactory);
}(angular));
locationServices.js
(function(angular) {
var LocationFactory = function($resource) {
return $resource('/location/:id', {
id : '#id'
}, {
update : {
method : "PUT"
},
remove : {
method : "DELETE"
}
});
};
LocationFactory.$inject = [ '$resource' ];
angular.module("myEventApp.services").factory("Location", LocationFactory);
}(angular));
So, the question is: how to automatically update the content of the combobox when a new location is added / a location is deleted? Thank you.

AngularJS - object not passed to modal dialog

I have a problem with an AngularJS app I'm making. It shows a list of contacts, and for each contact there is a button whereupon clicking the button a modal pops up with a form. This form should show the existing contact information, and if you want to change something you type the new information and press submit.
The problem, however, is that the existing information is not shown in the form, hence editing it doesn't work. I imagine that the issue is that the modal does not inherit the scope from the parent page, but I don't know what to do in order to fix that. I have tried playing around with the attributes on the input fields (for example prepending ng-model by $parent. and defining an ng-init value), but to no avail, so I hope some of the experts here will be able to point me on the right track.
Thank you in advance.
Now let me show you my code, so you can see the context I'm talking about. Here is the html that displays the list of contacts:
<div class="panel panel-default" ng-controller="contactsController">
<div class="panel-body">
<div id="gridContainer" ng-class="{'': state == 'list', 'none': state != 'list'}">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th scope="col"><spring:message code="contacts.name"/></th>
<th scope="col"><spring:message code="contacts.email"/></th>
<th scope="col"><spring:message code="contacts.phone"/></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="contact in page.source">
<td class="tdContactsCentered">{{contact.name}}</td>
<td class="tdContactsCentered">{{contact.email}}</td>
<td class="tdContactsCentered">{{contact.phoneNumber}}</td>
<td class="width15">
<div class="text-center">
<input type="hidden" value="{{contact.id}}"/>
<a ng-href="#updateContactsModal"
ng-click="selectedContact(contact);"
role="button"
title="<spring:message code="update"/> <spring:message code="contact"/>"
class="btn btn-sm btn-warning" data-toggle="modal">
<i class="icon-pencil"></i>
</a>
<a ng-href="#deleteContactsModal"
ng-click="selectedContact(contact);"
role="button"
title="<spring:message code="delete"/> <spring:message code="contact"/>"
class="btn btn-sm btn-danger" data-toggle="modal">
<em class="fa fa-trash"></em>
</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
And the html that defines the modal and the form:
<div id="updateContactsModal"
class="modal fade centering"
role="dialog"
aria-labelledby="updateContactsModalLabel"
aria-hidden="true" style="display: none;">
<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>
<h3 id="updateContactsModalLabel" class="modal-title">
<spring:message code="update"/> <spring:message code="contact"/>
</h3>
</div>
<div class="modal-body" data-ng-controller="contactsController">
<form name="updateContactForm" novalidate>
<input type="hidden"
required
data-ng-model="contact.id"
name="id"
value="{{contact.id}}"/>
<div>
<div class="form-group">
<label>* <spring:message code="contacts.name"/>:</label>
<input type="text"
autofocus
required
class="form-control"
data-ng-model="contact.name"
name="name"
placeholder="<spring:message code='contact'/> <spring:message code='contacts.name'/> "/>
<div>
<span class="alert alert-error"
ng-show="displayValidationError && updateContactForm.name.$error.required">
<spring:message code="required"/>
</span>
</div>
</div>
<div class="form-group">
<label>* <spring:message code="contacts.email"/>:</label>
<div class="input-append">
<input type="text"
required
class="form-control"
ng-model="contact.email"
name="email"
placeholder="<spring:message code='sample.email'/> "/>
</div>
<div>
<span class="alert alert-error"
ng-show="displayValidationError && updateContactForm.email.$error.required">
<spring:message code="required"/>
</span>
</div>
</div>
<div class="form-group">
<label>* <spring:message code="contacts.phone"/>:</label>
<div class="input-append">
<input type="text"
required
class="form-control"
ng-model="contact.phoneNumber"
name="phoneNumber"
placeholder="<spring:message code='sample.phone'/> "/>
</div>
<div>
<span class="alert alert-error"
ng-show="displayValidationError && updateContactForm.phoneNumber.$error.required">
<spring:message code="required"/>
</span>
</div>
</div>
</div>
</form>
<div class="modal-footer">
<input type="submit"
class="btn btn-primary"
ng-click="updateContact(updateContactForm);"
value='<spring:message code="update"/>'/>
<button class="btn btn-default"
data-dismiss="modal"
ng-click="exit('#updateContactsModal');"
aria-hidden="true">
<spring:message code="cancel"/></button>
</div>
</div>
<span class="alert alert-error dialogErrorMessage"
ng-show="errorOnSubmit">
<spring:message code="request.error"/>
</span>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
And finally the relevant parts of the controller:
App.controller('contactsController', ["$scope", "$http", function($scope,$http) {
$scope.pageToGet = 0;
$scope.state = 'busy';
$scope.lastAction = '';
$scope.url = "/uaiContacts/protected/contacts/";
$scope.errorOnSubmit = true;
$scope.errorIllegalAccess = false;
$scope.displayMessageToUser = false;
$scope.displayValidationError = false;
$scope.displaySearchMessage = false;
$scope.displaySearchButton = false;
$scope.displayCreateContactButton = false;
$scope.contact = {};
$scope.searchFor = "";
$scope.getContactList = function () {
var url = $scope.url;
$scope.lastAction = 'list';
$scope.startDialogAjaxRequest();
var config = {params: {page: $scope.pageToGet}};
$http.get(url, config)
.success(function (data) {
$scope.finishAjaxCallOnSuccess(data, null, false);
})
.error(function () {
$scope.state = 'error';
$scope.displayCreateContactButton = false;
});
};
$scope.populateTable = function (data) {
if (data.pagesCount > 0) {
$scope.state = 'list';
$scope.page = {source: data.contacts, currentPage: $scope.pageToGet, pagesCount: data.pagesCount, totalContacts : data.totalContacts};
if($scope.page.pagesCount <= $scope.page.currentPage){
$scope.pageToGet = $scope.page.pagesCount - 1;
$scope.page.currentPage = $scope.page.pagesCount - 1;
}
$scope.displayCreateContactButton = true;
$scope.displaySearchButton = true;
} else {
$scope.state = 'noresult';
$scope.displayCreateContactButton = true;
if(!$scope.searchFor){
$scope.displaySearchButton = false;
}
}
if (data.actionMessage || data.searchMessage) {
$scope.displayMessageToUser = $scope.lastAction != 'search';
$scope.page.actionMessage = data.actionMessage;
$scope.page.searchMessage = data.searchMessage;
} else {
$scope.displayMessageToUser = false;
}
};
$scope.exit = function (modalId) {
$(modalId).modal('hide');
$scope.contact = {};
$scope.errorOnSubmit = false;
$scope.errorIllegalAccess = false;
$scope.displayValidationError = false;
};
$scope.finishAjaxCallOnSuccess = function (data, modalId, isPagination) {
$scope.populateTable(data);
$("#loadingModal").modal('hide');
if(!isPagination){
if(modalId){
$scope.exit(modalId);
}
}
$scope.lastAction = '';
};
$scope.startDialogAjaxRequest = function () {
$scope.displayValidationError = false;
$("#loadingModal").modal('show');
$scope.previousState = $scope.state;
$scope.state = 'busy';
};
$scope.handleErrorInDialogs = function (status) {
$("#loadingModal").modal('hide');
$scope.state = $scope.previousState;
// illegal access
if(status == 403){
$scope.errorIllegalAccess = true;
return;
}
$scope.errorOnSubmit = true;
$scope.lastAction = '';
};
$scope.addSearchParametersIfNeeded = function(config, isPagination) {
if(!config.params){
config.params = {};
}
config.params.page = $scope.pageToGet;
if($scope.searchFor){
config.params.searchFor = $scope.searchFor;
}
};
$scope.selectedContact = function (contact) {
$scope.contact = angular.copy(contact);
debugger;
};
$scope.updateContact = function (updateContactForm) {
if (!updateContactForm.$valid) {
debugger;
$scope.displayValidationError = true;
return;
}
$scope.lastAction = 'update';
var url = $scope.url + $scope.contact.id;
$scope.startDialogAjaxRequest();
var config = {};
$scope.addSearchParametersIfNeeded(config, false);
$http.put(url, $scope.contact, config)
.success(function (data) {
$scope.finishAjaxCallOnSuccess(data, "#updateContactsModal", false);
})
.error(function(data, status, headers, config) {
$scope.handleErrorInDialogs(status);
});
};
$scope.getContactList();
}]);
The modal doesn't share the same scope as the contacts table because each time Angular finds another ng-controller directive, it creates a new scope.
You're declaring ng-scope in both the contacts table and the modal, which causes angular to create different scopes.
See this answer for more details:
https://stackoverflow.com/a/14462341/4938335
There are a few ways to solve this...
1) Put the modal HTML inside the parent element where you're already declaring ng-controller the first time - that way it will be part of the same scope
2) Use UI Bootstrap's modal directive to generate the modal with its own controller and pass in $scope.contact from your contactsController. See example here https://angular-ui.github.io/bootstrap/#/modal
3) Create a service that stores $scope.contact and inject that into a separate controller that you create for the modal. Here's someone else's fiddle that shows this:
http://jsfiddle.net/whnSs/

Directive Does Not Inherit Controller's Scope

I have a controller set up which contains a few functions to do form validation. In this controllers $scope I have an array $scope.errorMsgs that is populated with strings of error messages the user makes when filling out the form.
I also have a directive that displays this form. They are both attached to the same module. The controller and directive are in separate files within the same directory. However the scope in the directive's link function does not reference the $scope in the controller. They have different $ids in fact. Any ideas as to why this is happening?
Module:
angular.module('aop.availabilitysolver', [
'aop.services',
'checklist-model'
]).run(['widgetService', function(widgetService) { 'use strict';
widgetService.registerWidgets([
{
title: 'AVAILABILITYSOLVER.WIDGETS.AVAILABILITYSOLVER',
translatableDescription: 'AVAILABILITYSOLVER.WIDGETS.AVAILABILITYSOLVER',
type: 'aop-availability-solver',
configuration: {},
width: 1
}
]);
}]);
Controller
angular.module('aop.availabilitysolver')
.controller('AvailabilitySolverController', ['$scope',
function ($scope) { 'use strict';
//console.log($scope);
$scope.selectGoalDropdown = ['Impressions', 'Spend'];
$scope.selectGoalTimespan = ['Day', 'Week', 'Month'];
$scope.selectGoals = [
{
id: '1',
name: 'Impressions'
},
{
id: '2',
name: 'Spend'
}
];
$scope.selectTimespan = [
{
id: '4',
name: 'Day'
},
{
id: '5',
name: 'Week'
},
{
id: '6',
name: 'Month'
}
];
$scope.selectedItem = 'test2';
$scope.selectedItem1 = 'test3';
$scope.per = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20];
$scope.hours = [1, 3, 4, 12, 24, 36, 48, 72, 120, 168];
$scope.uncpd = ['uncapped'];
$scope.times = {
amt: [],
freq: [],
uncapped: []
};
$scope.caps = [];
$scope.quantity;
$scope.level = 'Fcap';
$scope.showErrors = false;
$scope.errorMsgs = [];
$scope.calculateFreqCaps = function(amt, freq, uncap) {
var rtn = [];
function isNothingSelected() { // No selections made
if(amt.length === 0 && freq.length === 0 && uncap.length === 0) {
rtn.push('Please choose frequency settings or select \'uncapped.\'');
$scope.errorMsgs.push('Please choose frequency settings or select \'uncapped.\'');
}
}
function malformedFrequencyOpts() { // Selected amount but no frequency & vice versa
if((amt.length > 0 && freq.length === 0) || (amt.length === 0 && freq.length > 0)) {
rtn.push('Please select both an amount and a frequency.');
$scope.errorMsgs.push('Please select both an amount and a frequency.');
}
}
function selectedTooMuch() { // Uncapped and frequency settings selected
if((amt.length > 0 || freq.length > 0) && uncap.length === 1) {
rtn.push('Choose uncapped only if no amount or frequency is selected');
$scope.errorMsgs.push('Choose uncapped only if no amount or frequency is selected');
}
}
isNothingSelected();
malformedFrequencyOpts();
selectedTooMuch();
if(rtn.length > 0) {
return rtn;
} else if (amt.length === 0 && freq.length === 0 && uncap.length === 1) { // Only uncapped selected
return ['uncapped'];
}
angular.forEach(amt, function (a) {
angular.forEach(freq, function (f) {
rtn.push(a + '/' + f + 'h');
});
});
return rtn;
};
$scope.validateSelectGoalQuantity = function(n) {
if(!Number(n)) {
$scope.errorMsgs.push('Quantity must be a number');
return false;
}
return true;
};
$scope.submitBtnClick = function() {
// Build Frequency cap JSON object
$scope.caps = $scope.calculateFreqCaps($scope.times.amt, $scope.times.freq, $scope.times.uncapped);
$scope.validateSelectGoalQuantity($scope.quantity);
if($scope.errorMsgs.length > 0) {
console.log($scope.errorMsgs);
// Show error message div and clear $scope.errorMsgs
$scope.showErrors = true;
//$scope.errorMsgs.length = 0;
}
else {
$scope.showErrors = false;
}
};
}]);
Directive
angular.module('aop.availabilitysolver')
.directive('aopAvailabilitySolver', ['$filter', function($filter) { 'use strict';
return {
restrict: 'E',
link: function(scope, element, attrs) {
angular.noop(attrs);
// Hide error div initially
$('.availabilitySolverErrorDisplay').hide();
var i = element.find('.levelRadio :radio');
i.on('click', function() {
if($(i[0]).prop('checked')) {
scope.level = 'Fcap';
element.find('.freqCapDiv').show();
}
else {
scope.level = 'Bid';
element.find('.freqCapDiv').hide();
}
});
console.log(scope);
},
templateUrl: 'features/availabilitySolver/availabilitySolver.html'
};
}]);
HTML
<div ng-controller="AvailabilitySolverController">
<div class="container-fluid availabilitySolverScreen1">
<div class="row">
<div class="alert alert-danger availabilitySolverErrorDisplay">
</div>
</div>
<div class="row">
Campaign Selector
</div>
<!-- Goals -->
<div class="row">
<h5>Select Goal</h5>
<form name="selectGoalForm" novalidate>
<div class="col-md-4">
<button name="goals" class="btn btn-default" ng-model="selectedItem" ng-options="value.id as value.name for (key, value) in selectGoals" data-style="btn-primary" bs-select></button>
</div>
<div class="col-md-4">
<div class="col-md-10">
<input type="number" name="quantity" class="form-control" placeholder="Quantity" ng-model="quantity">
</div>
<div class="col-md-2">
per
</div>
</div>
<div class="col-md-4">
<button name="timespan" class="btn btn-default" ng-model="selectedItem1" ng-options="value.id as value.name for (key, value) in selectTimespan" data-style="btn-primary" bs-select></button>
</div>
</form>
</div><!-- End goals -->
<!-- Level cap -->
<div class="row">
<h5>Level</h5>
<div class="col-md-12">
<form class="levelRadio">
<input name="level" value="Fcap" type="radio" checked> Fcap
<input name="level" value="Bid" type="radio"> Bid
</form>
</div>
</div><!-- end level cap -->
<!-- Frequency cap analysis -->
<div class="row freqCapDiv">
<h5>Customize Frequency Cap for Analysis</h5>
<div class="col-md-8">
<!-- per -->
<div class="col-md-4">
<ul>
<li ng-repeat="item in per">
<input type="checkbox"
checklist-value="item"
checklist-model="times.amt" /> {{item}} per
</li>
</ul>
</div><!-- end per -->
<!-- hour(s) -->
<div class="col-md-4">
<ul>
<li ng-repeat="item in hours">
<input type="checkbox"
checklist-value="item"
checklist-model="times.freq" /> {{item}} hr
</li>
</ul>
</div>
<!-- uncapped -->
<div class="col-md-4">
<ul>
<li ng-repeat="item in uncpd">
<input type="checkbox"
checklist-value="item"
checklist-model="times.uncapped" /> uncapped
</ul>
</div>
</div>
<div class="col-md-4">
</div>
</div><!-- end frequency cap analysis -->
<!-- submit button -->
<div class="row">
<button class="btn btn-primary" ng-click="submitBtnClick()">Submit</button>
</div>
</div>
</div>

Categories

Resources