I am relatively new to using Javascirpt and attempting to build a web map. I'm not able to toggle different attributes in my web map due to issues in the javascript file, which is my main issue after changing parameters many times.
Here's the code below;
HTML:
<div class="map-overlay" id="togglebox">
<div class="type" id="filter">
<div>
<input id='all' type='radio' name='toggle' value='all' checked='checked'>
<label for='all'>Display All</label>
<input id='Open' type='radio' name='toggle' value='Open'>
<label for='Open'>Open</label>
<input id='Closed' type='radio' name='toggle' value="Closed">
<label for='Closed'>Closed</label>
<input id='Malt' type='radio' name='toggle' value='Malt'>
<label for='Malt'>Malt</label>
<input id='Grain' type='radio' name='toggle' value='Grain'>
<label for='Grain'>Grain</label>
</div>
</div>
</div>
JS:
filterAccess = ['!=', ['get', 'type'], 'placeholder'];
document.getElementById('filter').addEventListener('change', (event) => {
const type = event.target.value;
console.log(type);
if (type == "all") {
filterAccess = ['!=', ['get', 'type'], 'placeholder'];
} else if (type == "Open") {
filterAccess = ['==', ['get', 'type'], 'Open'];
} else if (type == 'Closed') {
filterAccess = ['==', ['get', 'type'], 'Closed'];
} else if (type == 'Malt') {
filterAccess = ['==', ['get', 'type'], 'Malt'];
} else if (type == "Grain") {
filterAccess = ['==', ['get', 'type'], 'Grain'];
} else {
console.log("error");
}
map.setFilter("Whisky", ["all", filterAccess]);
});
I've tried going through mapbox help guides and tutorials but to no success.
<!-- HTML code with the filter toggle buttons -->
<div class="map-overlay" id="togglebox">
<div class="type" id="filter">
<div>
<input id='all' type='radio' name='toggle' value='all' checked='checked'>
<label for='all'>Display All</label>
<input id='Open' type='radio' name='toggle' value='Open'>
<label for='Open'>Open</label>
<input id='Closed' type='radio' name='toggle' value="Closed">
<label for='Closed'>Closed</label>
<input id='Malt' type='radio' name='toggle' value='Malt'>
<label for='Malt'>Malt</label>
<input id='Grain' type='radio' name='toggle' value='Grain'>
<label for='Grain'>Grain</label>
</div>
</div>
</div>
<!-- JavaScript code to initialize Mapbox and define the layer with the "Whisky" filter -->
<script>
// Replace YOUR_ACCESS_TOKEN with your Mapbox access token
mapboxgl.accessToken = 'YOUR_ACCESS_TOKEN';
var map = new mapboxgl.Map({
container: 'map', // Replace 'map' with the ID of your map container element
style: 'mapbox://styles/mapbox/streets-v11', // Replace with your Mapbox style URL
center: [-73.9749, 40.7736], // Replace with your preferred map center coordinates
zoom: 12 // Replace with your preferred map zoom level
});
// Add the "Whisky" layer with a default "all" filter
map.on('load', function() {
map.addLayer({
id: "Whisky",
type: "circle",
source: {
type: "geojson",
data: "path/to/your/geojson/file" // Replace with the URL or file path of your geojson data
},
paint: {
"circle-color": "#ff0000",
"circle-radius": 5
},
filter: ['!=', ['get', 'type'], 'placeholder']
});
});
// Add event listener to toggle the layer filter based on the selected toggle button
document.getElementById('filter').addEventListener('change', (event) => {
const type = event.target.value;
console.log(type);
if (type == "all") {
filterAccess = ['!=', ['get', 'type'], 'placeholder'];
} else if (type == "Open") {
filterAccess = ['==', ['get', 'type'], 'Open'];
} else if (type == 'Closed') {
filterAccess = ['==', ['get', 'type'], 'Closed'];
} else if (type == 'Malt') {
filterAccess = ['==', ['get', 'type'], 'Malt'];
} else if (type == "Grain") {
filterAccess = ['==', ['get', 'type'], 'Grain'];
} else {
console.log("error");
}
map.setFilter("Whisky", ["all", filterAccess]);
});
</script
Related
I want to be displayed the toastr popup message when the user try to insert the duplicate value for BageCode in form the if anyone can help me it will be so kind of him.
I the rest form column validation is working the toaster is working but I don't know how to compare the data from database and data in form
like this
if (this.form.BadgeCode == data.BadgeCode) {
toast.fire({
type: "warning",
title: "The badge code has already been taken."
});
}
Code in EmployeeController is:
public function index()
{
$date=\Carbon\Carbon::today();
// $this->authorize('isAdmin');
$employee=Employee::where('expiredate','>',$date)->paginate(5);
// return Employee::all();
return response()->json($employee);
}
public function store(Request $request)
{
// $this->authorize('isAdmin');
$this->validate($request,[
// 'BadgeCode'=>'required|string',
'BadgeCode'=>'required|unique:employees,BadgeCode',
'BadgeType'=>'required',
]) 'company_id'=>'required',
}
Code in api route is:
Route::apiResources(['employee'=>'API\EmployeeController']);
Code in Employee.vue is:
<div
style="width:45%;margin-left: 35%;"
class="modal fade"
id="addNew"
tabindex="-1"
role="dialog"
aria-labelledby="addNewLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" v-show="!editMode" id="addNewLabel">Add New employee</h5>
<h5 class="modal-title" v-show="editMode" id="addNewLabel">Update employee's Info</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form
#submit.prevent="editMode ? updateemployee() : createemployee()"
enctype="multipart/form-data"
>
<div class="modal-body">
<div class="form-group">
<select
name="company_id"
id="company_id"
:class="{'is-invalid':form.errors.has('company_id')}"
class="form-control"
v-model="form.company_id"
>
<option value selected>Select Company</option>
<option
v-for="Company in Companies"
:key="Company.id"
:value="Company.id"
>{{Company.Company}}</option>
</select>
<has-error :form="form" field="company_id"></has-error>
</div>
<div class="form-group">
<input
v-model="form.BadgeCode"
placeholder="Enter BadgeCode"
type="text"
name="BadgeCode"
class="form-control"
/>
<!-- :class="{ 'is-invalid': form.errors.has('BadgeCode') }" -->
<!-- <has-error :form="form" field="BadgeCode"></has-error> -->
</div>
<div class="form-group">
<select
name="BadgeType"
v-model="form.BadgeType"
id="BadgeType"
class="form-control"
:class="{'is-invalid':form.errors.has('BadgeType')}"
>
<option value selected>Select BadgeType</option>
<option value="Resident">Resident</option>
<option value="Non-Resident-Expat">Non-Resident Expat</option>
<option value="Non-Resident-LN">Non-Resident LN</option>
<option value="Baron-employee">Baron-employee</option>
</select>
<has-error :form="form" field="BadgeType"></has-error>
</div>
</div>
</form>
</div>
</div>
</div>
Code in script is:
<script>
export default {
// el: "#wrapper2",
data() {
return {
seen: false,
seen2: true,
color: "blue",
size: "20px",
editMode: false,
Companies: {},
employees: {},
form: new Form({
id: "",
BadgeCode: "",
BadgeType: "",
company_id: "",
})
};
},
methods: {
getvalidateion() {
axios.get("api/employee").then(response => {
let data = response.data.data;
if (data) {
data.forEach(element => {
if (this.form.BadgeCode == data.BadgeCode) {
toast.fire({
type: "warning",
title: "The badge code has already been taken."
});
}
});
} else {
console.log("NO DATA");
}
});
},
createemployee() {
this.getvalidateion();
if (this.form.company_id == "") {
toast.fire({
type: "warning",
title: "Please Select the Company."
});
} else if (this.form.BadgeCode == "") {
toast.fire({
type: "warning",
title: "BadgeCode is required."
});
} else if (this.form.BadgeType == "") {
toast.fire({
type: "warning",
title: "Please Select the BadgeType."
});
} else if (this.form.nationality_id == "") {
toast.fire({
type: "warning",
title: "Please Select the Nationality."
});
} else if (this.form.expiredate == "" || this.form.issuedate == "") {
toast.fire({
type: "warning",
title: "Please fill the issuedate or expiredate fileds ."
});
} else if (this.form.photo.length == "") {
toast.fire({
type: "warning",
title: "Please select photo."
});
} else if (
this.form.afghanidatephoto != undefined &&
this.form.afghanidatephoto.length == ""
) {
toast.fire({
type: "warning",
title: "Please select AfghaniDate."
});
} else {
this.form
.post("api/employee")
.then(() => {
// the below function will be use to reload the page
// this.$emit("refreshPage");
$("#addNew").modal("hide");
toast.fire({
type: "success",
title: "employee Created successfully"
});
this.form.reset();
$("#afghanidatephoto").val("");
$("#photo").val("");
Fire.$emit("refreshPage");
})
.catch(e => {
console.log(e);
});
}
},
created() {
Fire.$on("searching", () => {
let query = this.$parent.search;
axios
.get("api/findemployee?q=" + query)
.then(data => {
this.employees = data.data;
})
.catch(() => {});
});
this.loademployees();
this.getvalidateion();
// load the page after 3 secound
Fire.$on("refreshPage", () => {
this.loademployees();
});
}
};
</script>
Code in Modal is:
$table->string('BadgeCode')->unique();
I found the solution instate of data.BadgeCode I should have put element.BadgeCode anyway thanks guys
getvalidateion() {
axios.get(this.url).then(response => {
let data = response.data;
//this.Companies != undefined && this.Companies.length == 0
if (data) {
data.forEach(element => {
this.employees2.push(element.BadgeCode);
if (this.form.BadgeCode == element.BadgeCode) {
toast.fire({
type: "warning",
title: "BadgeCode is already has been taken."
});
}
});
} else {
console.log("NO DATA");
}
});
}
I am using jquery datatable with two checkbox columns with a checkall checkbox for each column in the table header. I am looping through all the checkboxes in the datatable for every change event on a checkbox to make sure the checkAll checkbox is checked/unchecked which results in a lag when user checks a checkbox.
Below is the code snippet. Please let me know if there any other way I can do this to improve the performance.
ntfcTable.$('.ntfcInd')
.change(
function() {
let counterNtfcCh = 0;
for (let i = 0; i < ntfcTableNodes.length; i++) {
if (ntfcTable.$('input[type="checkbox"][id="ntfcInd[' + i + ']"]').is(":checked") === true) {
counterNtfcCh++;
}
}
counterNtfcCh === ntfcTableNodes.length ? ntfcCheckAll.prop("checked", true)
: ntfcCheckAll.prop("checked", false);
checkBoxState = true;
});
Hopefully this will help. I am assuming that ntfcTable is a jQuery object. You don't need to search ntfcTable every time you loop through the table. The first line will grab all checkboxes in the table. jQuery objects have a length property so they can actually be looped over. This should work as long as you are not adding and removing checkboxes on the fly.
var ntfcTableNodes = ntfcTable.$('input[type="checkbox"]');
ntfcTableNodes.change(
function() {
let counterNtfcCh = 0;
for (let i = 0; i < ntfcTableNodes.length; i++) {
let checkNode = ntfcTableNodes[i];
if ( checkNode.is(":checked") === true ) {counterNtfcCh++;}
}
counterNtfcCh === ntfcTableNodes.length ? ntfcCheckAll.prop("checked", true)
: ntfcCheckAll.prop("checked", false);
checkBoxState = true;
});
Instead of looping through the checkboxes, you can just check the length of the checked checkboxes like this:
alert($('input[type="checkbox"]:checked').length);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox" name="vehicle" value="Bike"> I have a bike<br>
<input type="checkbox" name="vehicle" value="Car" checked> I have a car<br><input type="checkbox" name="vehicle" value="Bike"> I have a bike<br>
<input type="checkbox" name="vehicle" value="Car" checked> I have a car<br><input type="checkbox" name="vehicle" value="Bike"> I have a bike<br>
<input type="checkbox" name="vehicle" value="Car" checked> I have a car<br><input type="checkbox" name="vehicle" value="Bike"> I have a bike<br>
<input type="checkbox" name="vehicle" value="Car" checked> I have a car<br><input type="checkbox" name="vehicle" value="Bike"> I have a bike<br>
<input type="checkbox" name="vehicle" value="Car" checked> I have a car<br>
Or for you case, it's like this:
if(ntfcTable.$('input[type="checkbox"]:checked').length == ntfcTableNodes.length)
Even though, the question is marked 'Answered' to those, who may face that same problem, solution, for which OP has requested, basically, boils down to one nice and neat one-liner:
const ifAllChecked = col => dataTable.rows().nodes().toArray().every(row => $(row).find(`td:eq(${col}) [type="checkbox"]`).is(':checked'));
Following is the brief DEMO of how it can be done:
//define source data
const srcData = [
{city: 'Kyiv', visited: true, enjoyed: true},
{city: 'Istanbul', visited: true, enjoyed: true},
{city: 'Moscow', visited: true, enjoyed: false},
{city: 'Nicosia', visited: true, enjoyed: true},
{city: 'New York', visited: false, enjoyed: false},
{city: 'Cairo', visited: true, enjoyed: true}
];
//define datatables object
const dataTable = $('#mytable').DataTable({
sDom: 'tp',
pageLength: 3,
data: srcData,
columns: [
{title: 'city', data: 'city'},
{
title: 'visited',
data: 'visited',
render: (data, type, row, meta) => `<input type="checkbox" colindex="${meta.col}" ${data ? 'checked' : ''} style="float:right;margin-right:28px" class="regularchckbx"></input>`
},
{
title: 'enjoyed',
data: 'enjoyed',
render: (data, type, row, meta) => `<input type="checkbox" colindex="${meta.col}" ${data ? 'checked' : ''} style="float:right;margin-right:28px" class="regularchckbx"></input>`
},
]
});
//essential part of the solution OP was looking for
const ifAllChecked = col => dataTable.rows().nodes().toArray().every(row => $(row).find(`td:eq(${col}) [type="checkbox"]`).is(':checked'));
//put 'check all' checkboxes into header
$(dataTable.columns([1,2]).header()).append(`<input type="checkbox" class="allchecked" style="float:right;margin-right:20px"></input>`);
//set initial header checkboxes state
[1, 2].forEach( col => dataTable.column(col).header().querySelector('[type="checkbox"]').checked = ifAllChecked(col));
//listen for changes and adjust 'check-alls'
$('#mytable').on('click', '.regularchckbx', function(){
dataTable.column($(this).attr('colindex')).header().querySelector('[type="checkbox"]').checked = ifAllChecked($(this).attr('colindex'));
});
//check/uncheck all
$('.allchecked').on('click', function(){
let col = dataTable.column($(this).closest('th')).index();
let state = this.checked;
dataTable.rows().every(function(){
this.node().querySelector(`[colindex="${col}"]`).checked = state;
});
});
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
</head>
<body>
<table id="mytable"></table>
</body>
</html>
My html code is
I also need to add sez which is in array format and also i need to add multiple images, need to provide add image and when clicking on it, need to add images as needed by the client
<form method="POST" enctype="multipart/form-data" v-on:submit.prevent="handleSubmit($event);">
<div class="row">
<div class="col-md-4">
<div class="form-group label-floating">
<label class="control-label">Name</label>
<input type="text" class="form-control" v-model="name">
</div>
</div>
<div class="col-md-4">
<div class="form-group label-floating">
<label class="control-label">Alias</label>
<input type="text" class="form-control" v-model="alias">
</div>
</div>
<div class="col-md-4">
<div class="form-group label-floating">
<label class="control-label">Sex</label>
<select class="form-control" v-model="sex" id="level">
<option value="Male">Male</option>
<option value="female">Female</option>
</select>
</div>
</div>
</div>
<div class="row" v-for="(book, index) in sez" :key="index">
<div class="col-md-4">
<div class="form-group label-floating">
<label class="control-label">Date </label>
<input type="date" class="form-control" v-model="book.date">
</div>
</div>
<div class="col-md-8">
<div class="form-group label-floating">
<label class="control-label"> Details</label>
<input type="text" class="form-control" book.details>
</div>
</div>
</div>
<a #click="addNewRow">Add</a>
<div class="card-content">
<div class="row">
<div class="col-md-4">
<div class="button success expand radius">
<span id="save_image_titlebar_logo_live">Signature</span>
<label class="custom-file-upload"><input type="file" name="photo" accept="image/*" />
</label>
</div>
</div>
<div class="col-md-4">
<div class="button success expand radius">
<span id="save_image_titlebar_logo_live">Recent Photograph</span>
<label class="custom-file-upload">
<input type="file" name="sign"/>
</label>
</div>
</div>
</div>
</div>
</form>
My vue js code is
addForm = new Vue({
el: "#addForm",
data: {
name: '',
alias: '',
sex: '',
sez: [{
date: null,
details: null,
}, ],
photo: '',
sign: '',
},
methods: {
addNewRow: function() {
this.seziure.push({
date: null,
details: null,
});
},
handleSubmit: function(e) {
var vm = this;
data = {};
data['sez'] = this.sez;
data['name'] = this.name;
data['alias'] = this.alias;
data['sex'] = this.sex;
//how to add images
$.ajax({
url: 'http://localhost:4000/save/',
data: data,
type: 'POST',
dataType: 'json',
success: function(e) {
if (e.status) {
vm.response = e;
alert("success")
} else {
vm.response = e;
console.log(vm.response);
alert("Registration Failed")
}
}
});
return false;
},
},
});
This is my code. I have no idea about how to add images in this case.
Can anyone please help me pass this data.
How to pass this data along with images to the backend?
I don't want to use base64 encoding. I need to just pass this image in this ajax post request along with other data
Using axios:
Template
...
<input type="file" name="photo" accept="image/*" #change="setPhotoFiles($event.target.name, $event.target.files) />
...
Code
data () {
return {
...
photoFiles: [],
...
}
},
...
methods: {
...
setPhotoFiles (fieldName, fileList) {
this.photoFiles = fileList;
},
...
handleSubmit (e) {
const formData = new FormData();
formData.append('name', this.name);
formData.append('alias', this.alias);
formData.append('sex', this.sex);
...
this.photoFiles.forEach((element, index, array) => {
formData.append('photo-' + index, element);
});
axios.post("http://localhost:4000/save/", formData)
.then(function (result) {
console.log(result);
...
}, function (error) {
console.log(error);
...
});
}
}
I'm not sure where would you like the extra images to appear, but I added them after this column:
<div class="col-md-4">
<div class="button success expand radius">
<span id="save_image_titlebar_logo_live">Recent Photograph</span>
<label class="custom-file-upload">
<input type="file" name="sign"/>
</label>
</div>
</div>
And here's the column I added — "add images": (You can try this feature here, with the updates)
<div class="col-md-4">
<ul class="list-group" :if="images.length">
<li class="list-group-item" v-for="(f, index) in images" :key="index">
<button class="close" #click.prevent="removeImage(index, $event)">×</button>
<div class="button success expand radius">
<label class="custom-file-upload">
<input type="file" class="images[]" accept="image/*" #change="previewImage(index, $event)">
</label>
</div>
<div :class="'images[' + index + ']-preview image-preview'"></div>
</li>
</ul>
<button class="btn btn-link add-image" #click.prevent="addNewImage">Add Image</button>
</div>
And the full Vue JS code (with jQuery.ajax()):
addForm = new Vue({
el: "#addForm",
data: {
name: '',
alias: '',
sex: '',
sez: [{
date: null,
details: null
}],
// I removed `photo` and `sign` because (I think) the're not necessary.
// Add I added `images` so that we could easily add new images via Vue.
images: [],
maxImages: 5,
// Selector for the "Add Image" button. Try using (or you should use) ID
// instead; e.g. `button#add-image`. But it has to be a `button` element.
addImage: 'button.add-image'
},
methods: {
addNewRow: function() {
// I changed to `this.sez.push` because `this.seziure` is `undefined`.
this.sez.push({
date: null,
details: null
});
},
addNewImage: function(e) {
var n = this.maxImages || -1;
if (n && this.images.length < n) {
this.images.push('');
}
this.checkImages();
},
removeImage: function(index) {
this.images.splice(index, 1);
this.checkImages();
},
checkImages: function() {
var n = this.maxImages || -1;
if (n && this.images.length >= n) {
$(this.addImage, this.el).prop('disabled', true); // Disables the button.
} else {
$(this.addImage, this.el).prop('disabled', false); // Enables the button.
}
},
previewImage: function(index, e) {
var r = new FileReader(),
f = e.target.files[0];
r.addEventListener('load', function() {
$('[class~="images[' + index + ']-preview"]', this.el).html(
'<img src="' + r.result + '" class="thumbnail img-responsive">'
);
}, false);
if (f) {
r.readAsDataURL(f);
}
},
handleSubmit: function(e) {
var vm = this;
var data = new FormData(e.target);
data.append('sez', this.sez);
data.append('name', this.name);
data.append('alias', this.alias);
data.append('sex', this.sex);
// The `data` already contain the Signature and Recent Photograph images.
// Here we add the extra images as an array.
$('[class~="images[]"]', this.el).each(function(i) {
if (i > vm.maxImages - 1) {
return; // Max images reached.
}
data.append('images[' + i + ']', this.files[0]);
});
$.ajax({
url: 'http://localhost:4000/save/',
data: data,
type: 'POST',
dataType: 'json',
success: function(e) {
if (e.status) {
vm.response = e;
alert("success");
} else {
vm.response = e;
console.log(vm.response);
alert("Registration Failed");
}
},
cache: false,
contentType: false,
processData: false
});
return false;
},
},
});
Additional Notes
I know you're using Node.js in the back-end; however, I should mention that in PHP, the $_FILES variable would contain all the images (so long as the fields name are properly set); and I suppose Node.js has a similar variable or way of getting the files.
And in the following input, you may have forgotten to wrap book.details in v-model:
<input type="text" class="form-control" book.details>
<input type="text" class="form-control" v-model="book.details"> <!-- Correct -->
UPDATE
Added feature to limit number of images allowed to be selected/uploaded, and added preview for selected image. Plus the "send images as array" fix.
If you're using HTML5, try with a FormData object ; it will encode your file input content :
var myForm = document.getElementById('addForm');
formData = new FormData(myForm);
data: formData
Use below templete to show/upload the image:
<div v-if="!image">
<h2>Select an image</h2>
<input type="file" #change="onImageUpload">
</div>
<div v-else>
<img :src="image" />
<button #click="removeImage">Remove image</button>
</div>
Js code:
data: {
image: '',
imageBuff: ''
},
methods: {
onImageUpload(e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage(file) {
var image = new Image();
var reader = new FileReader();
this.imageBuff = file;
reader.onload = (e) => {
this.image = e.target.result;
};
reader.readAsDataURL(file);
},
removeImage: function(e) {
this.image = '';
},
handleSubmit(e) {
const formData = new FormData();
formData.append('name', this.name);
formData.append('alias', this.alias);
formData.append('sex', this.sex);
formData.append('image', this.imageBuff);
...
// Ajax or Axios can be used
$.ajax({
url: 'http://localhost:4000/save/',
data: formData,
processData: false, // prevent jQuery from automatically transforming the data into a query string.
contentType: false,
type: 'POST',
success: function(data) {
console.log(data);
...
}
});
}
}
I have some code that opens a modal that contains a form when a marker is placed on a layer in leaflet. It all worked well with out any issues. I copied this code so I could make a second button to control the opening of another modal containing a different form. I changed the link information but when the button is clicked the
L.DomEvent.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', L.bind(this.startCreating, this));
Opens up both forms at the same time or opens one then when closed and clicked againit will open both. Im not sure whats going on because each modal has a different ID.
Here is a live example of the map with the modals. Click the small elements/buttons on the left under the zoom control and drag the new market and click again to set its place on the map.
Leaflet Map with modals
Here is the JS code that should call the first modal called eventDataModal. The main link in the code is near the top:
L.MarkerControl = L.Control.extend({
options: {
position: 'topleft',
url: 'http://echostorm.mynetgear.com:8080/geoserver/usa/ows',
userName: 'wfspost',
password: 'createfeature'
},
map: null,
marker: null,
binded: false,
onAdd: function (map) {
this.map = map;
var container = L.DomUtil.create('div', 'leaflet-control leaflet-bar'),
// link = L.DomUtil.create('a', 'glyphicon glyphicon-map-marker', container);
link = L.DomUtil.create('a', 'glyphicon glyphicon-eye-open', container);
link.href = '#';
link.title = 'Create a new visual report';
link.innerHTML = '';
L.DomEvent.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', L.bind(this.startCreating, this));
map.on("editable:drawing:commit", L.bind(this.onMarkerAdd, this));
return container;
},
startCreating: function() {
this.marker = this.map.editTools.startMarker();
},
onMarkerAdd: function(e) {
this.nearestFeature = null;
this.findNearestPoints(e.layer.getLatLng());
},
onFormClosed: function() {
if (this.marker!=null) {
this.map.editTools.featuresLayer.removeLayer(this.marker);
this.marker = null;
}
},
findNearestPoints: function(latlng) {
var defaultParameters = {
service: 'WFS',
version: '1.0.0',
request: 'GetFeature',
typeName: 'usa:within5mi',
maxFeatures: 5,
outputFormat: 'text/javascript',
format_options: 'callback: nearestPoints',
srsName: 'EPSG:4326',
viewparams: 'radius:802;lon:'+latlng.lng+';lat:'+latlng.lat,
};
var parameters = L.Util.extend(defaultParameters);
$.ajax({
jsonp: false,
url: this.options.url + L.Util.getParamString(parameters),
dataType: 'jsonp',
jsonpCallback: 'nearestPoints',
success: L.bind(this.handleNearestPoints, this)
});
},
handleNearestPoints: function(data) {
this.clearModal();
this.setModalDate();
if (data && data.type=="FeatureCollection"
&& data.features && data.features.length
&& data.features.length > 0) {
this.fillModal(data.features[0]);
}
this.openPopup();
},
formatDate: function(date) {
var day = date.getDate();
return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+(day < 10 ? "0"+day : day);
},
clearModal: function() {
$('#eventDataModal').find('input').each(
function() {
$(this).val("");
}
);
$('#eventDataModal').find('textarea').each(
function() {
$(this).val("");
}
);
},
setModalDate: function() {
$("#form-patrolDate").val(this.formatDate(new Date()));
},
fillModal: function(feature) {
var props = feature.properties;
$("#form-region").val(props["Region"]);
$("#form-circuitID").val(props["Circuit_ID"]);
$("#form-circuitName").val(props["Circuit_Name"]);
$("#form-vendor").val(props["Vendor"]);
$("#form-quad").val(props["Quad"]);
},
openPopup: function() {
this.bindEvents();
$('#eventDataModal').modal('show');
},
bindEvents: function() {
if (!this.binded) {
$('#eventDataModal').on('hidden.bs.modal', L.bind(this.onFormClosed, this));
$("#saveEventDataModal").on('click', L.bind(this.onSave, this))
this.binded = true;
}
},
onSave: function() {
var properties = this.getFormData(),
request = this.wfsBody("usa", "usa:pecotest", "geom", properties);
console.log(request);
this.makeRequest(request);
},
makeRequest: function(body) {
$.ajax({
method: "POST",
crossDomain: true,
url: this.options.url,
contentType: "text/xml",
dataType: "text",
data: body,
headers: {
"Authorization": "Basic " + btoa(this.options.userName + ":" + this.options.password)
},
jsonpCallback: 'datasave',
success: L.bind(this.onDataSave, this),
failure: function(r){console.log("AJAX Failure!");console.log(r);}
});
},
onDataSave: function(data) {
console.log(data);
},
getFormData: function() {
var result = {};
$('#eventDataModal').find('input').each(
function() {
if (this.type=="checkbox") {
result[this.name] = this.checked ? "Yes" : "No";
} else {
result[this.name]=$(this).val();
}
}
);
$('#eventDataModal').find('textarea').each(
function() {
result[this.name]=$(this).val();
}
);
return result;
},
wfsBody: function(namesapce, typeName, geometryField, properties) {
var xml;
xml ='<wfs:Transaction service="WFS" version="1.0.0"';
xml += ' xmlns:wfs="http://www.opengis.net/wfs"';
xml += ' xmlns:usa="http://census.gov"';
xml += ' xmlns:gml="http://www.opengis.net/gml">\n';
xml += ' <wfs:Insert>\n';
xml += ' <'+typeName+'>\n';
xml += ' <usa:'+geometryField+'>\n';
xml += this.marker.toGML()+"\n";
xml += ' </usa:'+geometryField+'>\n';
for (var k in properties) {
if (properties.hasOwnProperty(k)) {
xml += "<"+namesapce+":"+k+">";
xml += properties[k];
xml += "</"+namesapce+":"+k+">\n";
}
}
xml += ' </'+typeName+'>\n';
xml += ' </wfs:Insert>\n';
xml += '</wfs:Transaction>\n';
return xml;
}
});
L.Marker.include({
toGML: function(){
var latlng = this.getLatLng(),
xml;
xml = '<gml:Point srsName="EPSG:4326"><gml:coordinates cs=","
decimal="." ts=" ">';
xml += latlng.lng + ',' + latlng.lat;
xml += '</gml:coordinates></gml:Point>';
return xml;
}
});
Here is the corresponding HTML for the modal evenDataModal
<div class="modal fade" id="eventDataModal">
<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">Create New Visual Report</h4>
</div>
<div class="modal-body">
<form action="php\new_peco_visual_report_db_insert.php
method="POST"><div class="form-group">
<label for="form-priority">ID Code</label>
<input type="number" class="form-control" id="form-priority"
name="ID_Code" placeholder="ID_Code">
</div>
<div class="form-group">
<label for="form-region">Region</label>
<input type="text" class="form-control" id="form-region"
name="Region" placeholder="region">
</div>
<div class="form-group">
<label for="form-circuitID">Circuit ID</label>
<input type="number" class="form-control" id="form-circuitID"
name="Circuit_ID" placeholder="Circuit ID">
</div>
<div class="form-group">
<label for="form-circuitName">Circuit Name</label>
<input type="text" class="form-control" id="form-circuitName"
name="Circuit_Name" placeholder="Circuit Name">
</div>
<div class="form-group">
<label for="form-patrolDate">Patrol Date</label>
<input type="date" class="form-control" id="form-patrolDate"
name="Patrol_Date" placeholder="Patrol Date">
</div>
<div class="form-group">
<label for="form-vendor">Vendor</label>
<input type="text" class="form-control" id="form-vendor"
name="Vendor" placeholder="Vendor">
</div>
<div class="form-group">
<label for="form-repairNumber">Repair Number</label>
<input type="text" class="form-control" id="form-repairNumber"
name="Repair_Number" placeholder="Repair Number">
</div>
<div class="form-group">
<label for="form-problemDescription"> Problem
Description</label>
<input type="text" class="form-control" id="form-
problemDescription" name="Problem_Description"
placeholder="Problem
Description">
</div>
<div class="form-group">
<label for="form-urgency">Priority</label>
<input type="number" class="form-control" id="form-urgency"
name="Urgency" placeholder="Urgency">
</div>
<div class="form-group">
<label for="form-circuitPortion">Circuit Portion</label>
<input type="text" class="form-control" id="form-circuitPortion"
name="Circuit_Portion" placeholder="Circuit Portion">
</div>
<div class="form-group">
<label for="form-quad">Quad</label>
<input type="text" class="form-control" id="form-quad"
name="Quad" placeholder="Quad">
</div>
<div class="form-group">
<label for="form-location">Location</label>
<input type="text" class="form-control" id="form-location"
name="Location" placeholder="location">
</div>
<div class="form-group">
<label for="form-poleSub">PolSub</label>
<input type="number" class="form-control" id="form-polSub"
name="PolSub" placeholder="PolSub">
</div>
<div class="form-group">
<label for="form-poleNumber">Pole Number</label>
<input type="number" class="form-control" id="form-poleNumber"
name="Pole_Number" placeholder="Pole Number">
</div>
<div class="form-group">
<label for="form-aerialName">Aerial Name</label>
<input type="text" class="form-control" id="form-aerialName"
name="Aerial_Name" placeholder="Aerial Name">
</div>
<div class="form-group">
<label for="form-workRequired">Work Required?</label>
<input type="text" class="form-control" id="form-workRequired"
name="Work_Required" placeholder="Work Required">
</div>
<div class="form-group">
<label for="form-long">GPS Longitude</label>
<input type="text" class="form-control" id="form-long"
name="long" placeholder="long">
</div>
<div class="form-group">
<label for="form-lat">GPS Latitude</label>
<input type="text" class="form-control" id="form-lat" name="lat"
placeholder="lat">
</div>
<div class="form-group">
<label for="form-notes">Comments</label>
<textarea class="form-control" id="form-comments"
name="Comments" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-
dismiss="modal">Close</button>
<button type="sumbit" class="btn btn-primary"
id="saveEventDataModal">Save</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
Here is the code for that should call the second modal called evenDataModal2
L.MarkerControl2 = L.Control.extend({
options: {
position: 'topleft',
url: 'http://echostorm.mynetgear.com:8080/geoserver/usa/ows',
userName: 'wfspost',
password: 'createfeature'
},
map: null,
marker: null,
binded: false,
onAdd: function (map) {
this.map = map;
var container = L.DomUtil.create('div', 'leaflet-control leaflet-bar'),
// link = L.DomUtil.create('a', 'glyphicon glyphicon-map-marker', container);
link = L.DomUtil.create('a', 'glyphicon glyphicon-fire', container);
link.href = '#';
link.title = 'Create a new thermal report';
link.innerHTML = '';
L.DomEvent.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', L.bind(this.startCreating, this));
map.on("editable:drawing:commit", L.bind(this.onMarkerAdd, this));
return container;
},
startCreating: function() {
this.marker = this.map.editTools.startMarker();
},
onMarkerAdd: function(e) {
this.nearestFeature = null;
this.findNearestPoints(e.layer.getLatLng());
},
onFormClosed: function() {
if (this.marker!=null) {
this.map.editTools.featuresLayer.removeLayer(this.marker);
this.marker = null;
}
},
findNearestPoints: function(latlng) {
var defaultParameters = {
service: 'WFS',
version: '1.0.0',
request: 'GetFeature',
typeName: 'usa:within5mi',
maxFeatures: 5,
outputFormat: 'text/javascript',
format_options: 'callback: nearestPoints',
srsName: 'EPSG:4326',
viewparams: 'radius:802;lon:'+latlng.lng+';lat:'+latlng.lat,
};
var parameters = L.Util.extend(defaultParameters);
$.ajax({
jsonp: false,
url: this.options.url + L.Util.getParamString(parameters),
dataType: 'jsonp',
jsonpCallback: 'nearestPoints',
success: L.bind(this.handleNearestPoints, this)
});
},
handleNearestPoints: function(data) {
this.clearModal();
this.setModalDate();
if (data && data.type=="FeatureCollection"
&& data.features && data.features.length
&& data.features.length > 0) {
this.fillModal(data.features[0]);
}
this.openPopup();
},
formatDate: function(date) {
var day = date.getDate();
return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+(day < 10 ? "0"+day : day);
},
clearModal: function() {
$('#eventDataModal2').find('input').each(
function() {
$(this).val("");
}
);
$('#eventDataModal2').find('textarea').each(
function() {
$(this).val("");
}
);
},
setModalDate: function() {
$("#form-patrolDate").val(this.formatDate(new Date()));
},
fillModal: function(feature) {
var props = feature.properties;
$("#form-region").val(props["Region"]);
$("#form-circuitID").val(props["Circuit_ID"]);
$("#form-circuitName").val(props["Circuit_Name"]);
$("#form-vendor").val(props["Vendor"]);
$("#form-quad").val(props["Quad"]);
},
openPopup: function() {
this.bindEvents();
$('#eventDataModal2').modal('show');
},
bindEvents: function() {
if (!this.binded) {
$('#eventDataModal2').on('hidden.bs.modal', L.bind(this.onFormClosed, this));
$("#saveEventDataModal2").on('click', L.bind(this.onSave, this))
this.binded = true;
}
},
onSave: function() {
var properties = this.getFormData(),
request = this.wfsBody("usa", "usa:pecotest", "geom", properties);
console.log(request);
this.makeRequest(request);
},
makeRequest: function(body) {
$.ajax({
method: "POST",
crossDomain: true,
url: this.options.url,
contentType: "text/xml",
dataType: "text",
data: body,
headers: {
"Authorization": "Basic " + btoa(this.options.userName + ":" + this.options.password)
},
jsonpCallback: 'datasave',
success: L.bind(this.onDataSave, this),
failure: function(r){console.log("AJAX Failure!");console.log(r);}
});
},
onDataSave: function(data) {
console.log(data);
},
getFormData: function() {
var result = {};
$('#eventDataModal2').find('input').each(
function() {
if (this.type=="checkbox") {
result[this.name] = this.checked ? "Yes" : "No";
} else {
result[this.name]=$(this).val();
}
}
);
$('#eventDataModal2').find('textarea').each(
function() {
result[this.name]=$(this).val();
}
);
return result;
},
wfsBody: function(namesapce, typeName, geometryField, properties) {
var xml;
xml ='<wfs:Transaction service="WFS" version="1.0.0"';
xml += ' xmlns:wfs="http://www.opengis.net/wfs"';
xml += ' xmlns:usa="http://census.gov"';
xml += ' xmlns:gml="http://www.opengis.net/gml">\n';
xml += ' <wfs:Insert>\n';
xml += ' <'+typeName+'>\n';
xml += ' <usa:'+geometryField+'>\n';
xml += this.marker.toGML()+"\n";
xml += ' </usa:'+geometryField+'>\n';
for (var k in properties) {
if (properties.hasOwnProperty(k)) {
xml += "<"+namesapce+":"+k+">";
xml += properties[k];
xml += "</"+namesapce+":"+k+">\n";
}
}
xml += ' </'+typeName+'>\n';
xml += ' </wfs:Insert>\n';
xml += '</wfs:Transaction>\n';
return xml;
}
});
The corresponding HTML for eventDataModal is exactly the same as the above html code except the id has been changed to eventDataModal2
I'm wondering if this is possible or not. When the user hits the save button, I want knockout to check if the field labeled Status has been changed to Completed - then I want it to enter the current date into the Date Completed field.
Here are my fields -
<ul class="button-group">
<li><button data-bind="click: save" class="success">Save</button></li>
<li><button data-bind="click: saveAndClose" class="success">Save and close</button></li>
<li><button data-bind="click: cancel" class="alert">Cancel</button></li>
</ul>
<div data-bind="with: item">
<label for="Type">Type</label>
<input id="Type" data-bind="value: Type" disabled="disabled" type="text" />
<label for="Status">Status</label>
<select id ="Status" data-bind="value: Status">
<option value="Not Started">Not Started</option>
<option value="In Progress">In Progress</option>
<option value="Completed">Completed</option>
</select>
<label for="Subject">Subject</label>
<input id="Subject" data-bind="value: Subject" type="text"/>
<label for="Content">Content</label>
<textarea id="Content" data-bind="value: Content" type="text"></textarea>
label for="DateCreated">Date Created (DD/MM/YYYY)</label>
<input id="DateCreated" disabled data-bind="valueFormat: DateCreated, type: 'datetime', format: 'DD/MM/YYYY'" type="text" placeholder="Enter date in format DD/MM/YYYY" />
<label for="DateLastModified">Date Last Modified (DD/MM/YYYY)</label>
<input id="DateLastModified" data-bind="valueFormat: DateLastModified, type: 'datetime', format: 'DD/MM/YYYY'" type="text" placeholder="Enter date in format DD/MM/YYYY" />
<label for="DateCompleted">Date Completed (DD/MM/YYYY)</label>
<input id="DateCompleted" data-bind="valueFormat: DateCompleted, type: 'datetime', format: 'DD/MM/YYYY'" type="text" placeholder="Enter date in format DD/MM/YYYY" />
</div>
And heres what my js file consists of so far
var Module = function(){
var self = this;
var updateItem = function(item) {
if (item) {
self.setupEntityValidation(item, self);
self.item(item);
}
};
self.title = ko.observable();
self.item = ko.observable();
self.isLoadingData = ko.observable(true);
self.entityName = 'Task';
self.entityId = null;
self.activate = function(cid, idOrNew, newType) {
var loadedItem,
types = {
task: {
type: 'Task',
newStatus: 'Not Started'
},
phone: {
type: 'Phone',
newStatus: 'Completed'
},
email: {
type: 'Email',
newStatus: 'Completed'
},
note: {
type: 'Note',
newStatus: 'Completed'
}
},
now = null,
mode = 'new' === idOrNew ? 'Create new' : 'Edit';
// Page title
self.entityId = 'new' === idOrNew ? 0 : parseInt(idOrNew);
self.title(mode + ' task');
if ('new' !== idOrNew) {
// Load the item
self.isLoadingData = ko.observable(true);
ds.getEntityWithKey('Task', self.entityId)
.then(function(data) {
if (data && data.entity) {
// Load item
updateItem(data.entity);
} else {
log.error('#todo get by id failed with result', data);
}
})
.fail(function(err) {
log.error('#todo get by id failed completely', err.stack);
})
.finally(function() {
self.isLoadingData(false);
});
} else {
// No id, create new. Check newType is valid
if (types.hasOwnProperty(newType)) {
// Create new task
now = new Date();
loadedItem = ds.createEntity('Task', {
CentreID: parseInt(cid),
Type: types[newType].type,
Status: types[newType].newStatus,
DateCreated: now.toISOString()
});
if (loadedItem) {
updateItem(loadedItem);
} else {
log.error('Could not create new task item');
}
} else {
log.error('Cannot create new task, illegal type:' + newType);
}
self.isLoadingData(false);
}
};
};
var moduleInstance = new Module();
modex.addComponent('EntitySaveCancel', moduleInstance);
modex.addComponent('EntityValidation', moduleInstance);
return moduleInstance;
});
If you want to instantly apply the change when the field changes to "Completed" you can add a subscribe function that watches the observable "Status" for any change:
self.Status.subscribe(function (value) {
if (value === "Completed") {
//Change date here.
}
});
If you want to change it upon clicking save, you can check "Status" observable value there and set the date accordingly.
Please let us know if this works with you.