How to get element attributes onAutocomplete with Materialize - javascript

I am using the same Materialize Autocomplete on 3 input elements. Then on onAutocomplete() I need to get the ID of the element the autocomplete was used on so I can populate data in the right place. So I want to know if it was either autocomplete-input1 or autocomplete-input2. How can I do that in pure javascript?
<div class="col s12">
<div class="row">
<div class="input-field col s6">
<input type="text" id="autocomplete-input1" class="autocomplete" autocomplete="off">
<label for="autocomplete-input1">Input1: Type my name - Radek</label>
</div>
<div class="input-field col s6">
<input type="text" id="autocomplete-input2" class="autocomplete" autocomplete="off">
<label for="autocomplete-input2">Input2: Type my name - Radek</label>
</div>
</div>
</div>
I want to know the ID of element user typed something and use the autocomplete. The javascript code would be part of the onAutocomplete function. I tried few options but none worked.
$(function () {
$('input.autocomplete').autocomplete({
data: {
"Radek Surname <br> radeksurname#ymail.com": null,
"Radek": null,
"Radoslav": 'http://placehold.it/250x250'
},
onAutocomplete: function(txt) {
console.log(this.getAttribute("id"));
console.log(this.id);
console.log(this.innerHTML);
console.log(this.innerText);
console.log(this.outerHTML);
},
limit: 20,
});
});
You can use this jsFiddle and fiddle around ..

Example 1 - JsFiddle
$(function () {
const selector = 'input.autocomplete';
let currentActiveAutoCompleteInput = null;
document.querySelectorAll(selector).forEach(el => {
el.onchange = function(evt) {
currentActiveAutoCompleteInput = evt.target;
};
});
$(selector).autocomplete({
data: {
"Radek Surname <br> radeksurname#ymail.com": null,
"Radek": null,
"Radoslav": 'http://placehold.it/250x250'
},
onAutocomplete: function(txt) {
console.log(currentActiveAutoCompleteInput.id);
},
limit: 20,
});
});
Example 2 - JsFiddle
$(function () {
let currentActiveAutoCompleteInput = null;
$('input.autocomplete')
.on('change', function(evt) {
currentActiveAutoCompleteInput = evt.target;
})
.autocomplete({
data: {
"Radek Surname <br> radeksurname#ymail.com": null,
"Radek": null,
"Radoslav": 'http://placehold.it/250x250'
},
onAutocomplete: function(txt) {
console.log(currentActiveAutoCompleteInput.id);
},
limit: 20,
});
});

Related

Dropzone instance works on first element but not cloned elements (Vue)

I have a snippet below which is essentially my entire code block at this point, and essentially it creates a div and when you click "add another zone" it will clone that div. This allows the user to enter multiple lines of info and each have their own result and image.
The issue is that I'm successfully cloning everything with it's own unique identity thanks to my card setup. However, dropzone is not replicating. The first file dropzone form will work perfectly, but when I clone the div and have 2 or more dropzone insnstances on the page they don't work (they don't show the upload image text or anything)
How can I successfully apply my same logic to the dropzone instance here?
new Vue({
components: {},
el: "#commonNameDiv",
data() {
return {
searchString: [''],
results: [],
savedAttributes: [],
cards: [],
showList: false,
zoneNumber:[],
imageZoneNames: [] }
},
methods: {
autoComplete(ev, card) {
this.results = [];
console.log(this.searchString);
if (ev.target.value.length > 2) {
axios.get('/product/parts/components/search', {
params: {
searchString: ev.target.value
}
}).then(response => {
card.results = response.data;
this.showList = true;
console.log(this.results);
console.log(this.searchString);
});
}
},
saveAttribute(result, card) {
card.value = result.attribute_value;
card.results = [];
card.zone = this.zoneNumber;
this.showList = false;
},
addCard: function() {
this.cards.push({
index: "",
value: "",
zoneNumber: "",
results: [],
componentImage:""
});
console.log(this.cards);
},
hideDropdown() {
this.showList = false;
},
},
created() {
this.addCard();
let instance = this;
Dropzone.options = {
maxFilesize: 12,
renameFile: function (file) {
var dt = new Date();
var time = dt.getTime();
return time + file.name;
},
acceptedFiles: ".jpeg,.jpg,.png,.gif",
addRemoveLinks: true,
timeout: 50000,
removedfile: function (file) {
console.log(file.upload.filename);
var name = file.upload.filename;
var fileRef;
return (fileRef = file.previewElement) != null ?
fileRef.parentNode.removeChild(file.previewElement) : void 0;
},
init: function() {
this.on("addedfile",
function(file) {
instance.imageZoneNames.push({name: file.upload.filename, desc: 'Line Drawing'});
console.log(file);
console.log(instance.imageZoneNames);
});
}
};
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.js"></script>
<div id="commonNameDiv">
<div class="uk-grid" v-for="(card, i) in cards" :key="i">
<div class="uk-width-1-10" >
<input v-model=" card.zoneNumber" size="4" type="text" name="mapNumber">
</div>
<div class="uk-width-6-10">
<input
style="width:100%"
placeholder="what are you looking for?"
v-model="card.value"
v-on:keyup="autoComplete($event, card)"
>
<div v-if="showList" class="panel-footer componentList" v-if="card.results.length">
<ul>
<li v-for="(result, i) in card.results" :key="i">
<a v-on:click="saveAttribute(result, card)">#{{ result.attribute_value }}</a>
</li>
</ul>
</div>
</div>
<div class="uk-width-3-10">
<form method="post" action="{{url('product/parts/upload/store')}}" enctype="multipart/form-data"
class="dropzone">
</form>
</div>
</div>
<div style="height: 35px;">
</div>
<div>
<a v-on:click="addCard">Add another zone</a>
</div>
</div>
When you instantiate the Dropzone class, it automatically looks for elements to transform in dropzones (by default, elements with the .dropzone class).
It looks like you want to dynamically add elements that are dropzones. Then you need to trigger the dropzone transformation yourself.
I would suggest you disable the autoDiscover option, and manually designates each element you want to transform into dropzones :
addCard() {
this.cards.push({
...
});
let cardIndex = this.cards.length - 1;
// Waiting for the element #dropzone-X to exist in DOM
Vue.nextTick(function () {
new Dropzone("#dropzone-"+cardIndex, {
...
});
});
},
created() {
...
Dropzone.autoDiscover = false
// no new Dropzone()
...
// Starting setup
this.addCard();
},
<form ... class="dropzone" v-bind:id="'dropzone-'+i">
Working jsbin
There are several ways to select the element to transform ($refs, ids, classes), here I'm suggesting ids.
See the doc on programmatically creating dropzones
Actually it is being created, but the Dropzone is not being reconstructed.
I think you have to create a new instance of the Dropzone.
if you try to insert:
created() {
this.addCard();
var myDropzone = new Dropzone('.dropzone')
let instance = this;
Dropzone.options.myDropzone = {
or even add the options to the addCard method or set a setupDropzones method and add it to the addCard method.

How can I add multiple images along with other input fields in vue js 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);
...
}
});
}
}

how to update a start and end page input field automatically

I have a list of start and end page numbers using angularJS forms. What i want to do is...for example if a user has entered the end page to be 4 on the first row, then I want the start page of the second row to be automatically updated with 5 (+1 of the previous end page).
I'm using an object that looks like this:
$scope.pages = {
items: [{
startNumber: 1,
endNumber: ''
},
{
startNumber: '',
endNumber: ''
},
{
startNumber: '',
endNumber: ''
},
{
startNumber: '',
endNumber: ''
}
]
};
HTML:
<div class="form-group col-sm-3" ng-repeat="file in pages.items">
<label for="start">Pages </label>
<input type="number" name="startPage" class="form-control" id="start" ng-model="file.startNumber">
<label for="end"> - </label>
<input type="number" name="endPage" class="form-control" id="end" ng-model="file.endNumber">
</div>
Function:
$scope.autoStartPageNumber = function(endPage) {
if (endPage.length) {
startNumber = endNumber + 1;
}
};
I'm not sure if i'm using the function correctly or where to put the function to add the numbers. If anyone has done anything similar to this..any help would be great
You can use ng-change on second input field and update the field accordingy. You can do something like this.
$scope.autoStartPageNumber = function(index) {
if (index + 1 < $scope.pages.items.length) {
$scope.pages.items[index + 1].startNumber = 1 + $scope.pages.items[index].endNumber;
}
};
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.pages = {
items:[
{
startNumber:1,
endNumber:''
},
{
startNumber:'',
endNumber:''
},
{
startNumber:'',
endNumber:''
},
{
startNumber:'',
endNumber:''
}
]
};
$scope.autoStartPageNumber = function (index) {
if(index +1 < $scope.pages.items.length){
$scope.pages.items[index+1].startNumber=$scope.pages.items[index].endNumber + 1;
}
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="form-group col-sm-3" ng-repeat="file in pages.items">
<label for="start">Pages </label>
<input type="number" name="startPage" class="form-control" id="start" ng-model="file.startNumber">
<label for="end"> - </label>
<input type="number" name="endPage" class="form-control" id="end" ng-model="file.endNumber" ng-change="autoStartPageNumber($index)">
</div>
</div>

how to remove specific character and text

I have finish autocomplete with a jquery library which is
using jquery-ui-1.12.1.min.js
. I have modified it to make to get the search with username and full name. it will show as below image
when I select the value it will paste the whole text into an input box.
here is my question how do it modify it to show as the image but when I select the value it will only paste the username into input box?
how i only want nonstop00000 paste it into input box when i select the 1st value
here is my javascript
$(document).ready(function () {
$("#id").autocomplete({
source: function(request,response) {
$.ajax({
url: '#Url.Content("~/UserManagement/AutoCompleteUser")/',
type: "POST",
dataType: "json",
data: { term: request.term },
success: function (data) {
response($.map(data, function (item) {
return [{ label: item.Username + " | " + item.FullName, value: item.id }];
}))
}
})
},
messages: {
noResults: "", results: ""
}
});
})
here is my search controller
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.Username.Trim().Contains(searchString.Trim())
|| s.FullName.Trim().Contains(searchString.Trim()));
}
here is my autocomplete controller
public JsonResult AutoCompleteUser(string term)
{
var result = (from r in db.UserTables
where ((r.Status == "Active") && (r.Username.ToLower().Contains(term.ToLower()) || (r.FullName.ToLower().Contains(term.ToLower()))))
select new { Username = r.Username, FullName = r.FullName }).Distinct();
return Json(result);
}
here is my view
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-12 search-panel">
#using (Html.BeginForm("Index", "UserManagement", FormMethod.Get))
{
<div class="input-group form-group ui-widget">
#Html.TextBox("id", ViewBag.CurrentFilter as string, new { #class = "form-control autocomplete", #placeholder = "Search for..." })
<span class="input-group-btn">
<input type="submit" value="Search" class="form-control autocomplete " />
</span>
</div>
}
</div>
To achieve this you can use the select event to amend the value to be placed in to the input. Try this:
$("#id").autocomplete({
// your settings...
select: function(e, ui) {
e.preventDefault();
$('#id').val(ui.item.label.split('|')[0].trim());
}
});

Login with enter key pressed knockout js

I have been trying to get my login page to work once I pressed the enter key, but it doesn't work. Help anyone?
Here is my codes:
Javascript/ viewModel:
ko.bindingHandlers.enterkey = {
init: function (element, valueAccessor, allBindings, viewModel) {
var callback = valueAccessor();
$(element).keypress(function (event) {
var keyCode = (event.which ? event.which : event.keyCode);
if (keyCode === 13) {
callback.call(viewModel);
return false;
}
return true;
});
}
};
Mobile.Login = function (params) {
var viewModel = {
dxPasswordTB: {
value: ko.observable(""),
showClearButton: true,
placeholder: ko.observable("PASSWORD"),
mode: 'password'
},
validateAndSubmit: function (params) {
var result = params.validationGroup.validate();
...
},
};
return viewModel;
};
View/ HTML:
<div class="row">
<div class="col-sm-12 col-xs-12">
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><i class="icon-password"></i></span>
<div class="form-control">
<div data-bind="dxTextBox: dxPasswordTB, dxValidator: PasswordVR, valueUpdate: 'afterkeydown', enterkey: validateAndSubmit""></div>
</div>
</div>
</div>
</div>
</div>
Any idea what went wrong here? If you do, please post your suggestions here, thanks!
I managed to resolve this by using onEnterKeyin dxPasswordTB from devExpress. Also, I changed params.validationGroup.validate(); to DevExpress.validationEngine.validateGroup() and the value was finally defined.

Categories