Why my <script> doesn't enable/disable the specific submit-button? - javascript

I'm working with Laravel 5 and I've the following HTML pages:
HTML 1
<div class="row">
#foreach($postList as $post)
#include('Pages.Post.postInGroup', ['post'=>$post, 'commentsList'=>$commentsList])
#endforeach
</div>
HTML 2
<form id="msform" action="{{route('comments.store')}}" method="post">
{{ csrf_field() }}
<div class="row align-items-center">
<div class="col-3 col-sm-3 col-md-2 col-lg-2 col-xl-1" style="display: inline-block;">
<img src="{{url(Auth::user()->picture_path)}}" style="border-radius: 50%;" width="30" height="30" alt="User Picture">
</div>
<div class="col-9 col-sm-9 col-md-6 col-lg-6 col-xl-9" style="display: inline-block;">
<textarea class="form-control" placeholder="Post a comment" id="comment_content {{$post->id}}" name="comment_content" rows="1"></textarea>
</div>
<div class="col-1 col-sm-1 col-md-1 col-lg-1 col-xl-1" >
<input type="submit" name="comment_button {{$post->id}}" class="btn btn-primary" value="Comment" style="background-color: #228B22;"/>
<input type="hidden" value="{{$post->id}}" name="postId" id="postId">
<input type="hidden" value="{{$theGroup->id}}" name="groupId" id="groupId">
</div>
</div>
</form>
<script src="{{ url('js/jquery-3.3.1.min.js') }}"></script>
<script>
$(document).ready(function() {
$('#msform > div > div > input[name=comment_button {{$post->id}}]').prop('disabled', true);
//while user is typing disable and enable based on the value.
$('#msform > div textarea').on("input", function() {
$(this).parents('.row').find('input[name=comment_button {{$post->id}}]').prop('disabled', $(this).val() == '');
});
});
</script>
The HTML 1 code explains how the HTML 2 code is repeated based on the number of objects in $postList.
What I'm trying to do is disable the button corresponding to the textarea, as long as its textarea is empty, but I do not get the desired result, because when I fill in any textarea, all the buttons are re-abilitated, and that's not what I want. For reasons of data extrapolation, I cannot change the name of the textarea and I would like this script works only on the submit button in HTML 2.
To explain better my problem, I'll made an example:
I have cycled 3 times HTML 2 by HTML 1, so I'll have:
Textarea(id="comment_content 1") - Button (name="comment_button 1")
Textarea(id="comment_content 2") - Button (name="comment_button 2")
Textarea(id="comment_content 3") - Button (name="comment_button 3")
If I want to write in the 2nd textarea with id comment_content 2, then I will have to enable only the button adjacent to that textarea, comment_button 2. I hope my problem is clear.

You're including the same external script and same inline script multiple times, as many times as there are posts. This is inefficient, you should include the external Javascript only once per page.
You can refactor this code to address your bug by creating a listener that listens to all textareas and then uses a data attribute on the textarea to determine which button should have a state change.
Step 1: Add the post ID to the textarea in a data attribute
<textarea data-post="{{ $post->id }}"
class="form-control"
placeholder="Post a comment"
id="comment_content {{$post->id}}"
name="comment_content" rows="1"></textarea>
Step 2: Add the post ID to the button in a data attribute
<input data-post="{{ $post->id }}"
type="submit"
name="comment_button {{$post->id}}"
class="btn btn-primary"
value="Comment"
style="background-color: #228B22;"/>
Step 3: Refactor your Javascript to use the data-post value when determining what the user is interacting with, e.g:
$(document).ready(function() {
$('#msform > textarea[data-post]').on("input", function() {
var id = $(this).data('post');
$('input[data-post="' + id + '"]').prop('disabled', $(this).val() == '');
});
});
Here's an example of how it'll work, click "Run code snippet" to see it in action.
$(document).ready(function() {
$('textarea[data-post]').on("input", function() {
var id = $(this).data('post');
$('input[data-post="' + id + '"]').prop('disabled', $(this).val() == '');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<textarea data-post="1"></textarea>
<input data-post="1" type="submit" disabled="true"/>
</div>
<div>
<textarea data-post="2"></textarea>
<input data-post="2" type="submit" disabled="true"/>
</div>
<div>
<textarea data-post="3"></textarea>
<input data-post="3" type="submit" disabled="true"/>
</div>

Related

How to use HTML template tag with jQuery?

Something strange bug is going on in my code. I want to use HTML template tag with jQuery, because all the rest of my code is jQuery, but I only found JavaScript examples with it. I tried to "translate" from JavaScript to jQuery, this is what I came up with.
$.getJSON( "../Controller/ControllerBookstore.php?show_books=true", function( data ) {
$.each( data, function( index, value ) {
// let clone = document.getElementById('table-template').content.cloneNode(true);
// clone.querySelector('#id').innerText = value.id;
// clone.querySelector('#author').innerText = value.author;
// clone.querySelector('#title').innerText = value.title;
// clone.querySelector('#isbn').innerText = value.isbn;
let clone = $("#table-template").clone(true);
$("#id",clone).text(value.id);
$("#author",clone).text(value.author);
$("#title",clone).text(value.title);
$("#isbn",clone).text(value.isbn);
//$(".container").append(clone);
$("#header").append(clone);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div id="myAlert" class="alert alert-success collapse">
<span id="alert-text"></span>
<a id="alert-close" class="close" href="#" aria-label="Close">×</a>
</div>
<div class="row" id="header">
<div class="col"><h5>ID</h5></div>
<div class="col"><h5>Author</h5></div>
<div class="col"><h5>Title</h5></div>
<div class="col"><h5>ISBN</h5></div>
<div class="col"><h5>Action</h5></div>
</div>
<template id="table-template">
<div class="row">
<div class="col" id="id"></div>
<div class="col" id="author"></div>
<div class="col" id="title"></div>
<div class="col" id="isbn"></div>
<div class="col buttons">
<button class='btn btn-info edit'>Edit</button>
<button class='btn btn-danger delete'>Delete</button>
</div>
</div>
</template>
<div class="row justify-content-center" >
<form action="" class="col-4">
<input id = "id-box" type="hidden" name="id">
<div class="form-group row">
<label class="col-4">Author</label>
<input id = "author-box" type="text" class="form-control col-8" name="author" placeholder="Enter the author of the book">
</div>
<div class="form-group row">
<label class="col-4">Title</label>
<input id = "title-box" type="text" class="form-control col-8" name="title" placeholder="Enter the title of the book">
</div>
<div class="form-group row">
<label class="col-4">ISBN</label>
<input id = "isbn-box" type="text" class="form-control col-8" name="isbn" placeholder="Enter the ISBN of the book">
</div>
<div class="form-group row">
<button id = "submit" type="submit" name="save" class="btn btn-primary col-12">Save</button>
</div>
</form>
</div>
</div>
For some reason the JavaScript code I commented out works, but it only appends "clone" to my ".container" correctly, on the next line below the form. However I want to attach it to my ".header", but it attaches next to the header, not below it. The jQuery code doesn't do anything, it doesn't attach my "clone" anywhere.
I hope I was clear. Could you please help me to find the reason of the bugs?
A few changes are needed:
The id value of the template has a hyphen which must be escaped in the selector. Two backslashes are needed in the string literal; the first is needed to actually get a backslash in the string. The remaining one will be interpreted by the selector.
Clone the row element within the template, not the template itself. However, jQuery will not know of a DOM within the template tag, so you could just take the HTML content instead of cloning, and then turn that into a jQuery object again (which produces the DOM for it).
Insert the clone just before the template
Code:
let clone = $($("#table\\-template").html()); // <--------
$("#id",clone).text(value.id);
$("#author",clone).text(value.author);
$("#title",clone).text(value.title);
$("#isbn",clone).text(value.isbn);
$("#table-template").before(clone); // <------
As others have commented, id attributes should have unique values, so your template content cannot have id properties (since it gets cloned). Use class attributes instead.
jQuery bug
Hello my friend. You are cloning the incorrect element, because your create a clone of template with the id #table-template. Please, make this change to your code:
...
let clone = $("#table-template").html();
...
The other thing, the cloned code appears next to #header and not below it because you are using a .row class. I propose to create a div below the #header, with the id="body" and append the new content inside:
...
// $("#header").append(clone);
-> $("#body").append(clone);
...
Thanks for the example.
But I don't change the id of the "collapse" div.
The rest of the objects are cloned normally.
<template id="facilities_template">
<div class="collapse">
<div class="form-check icon-check">
<input class="form-check-input" type="checkbox">
<label class="form-check-label font-14" id="facilities_name" ></label>
<i class="icon-check-1 far fa-square color-gray-dark font-20"></i>
<i class="icon-check-2 fa fa-check-square font-20 color-green-dark"></i>
</div>
<div class="mb-3"></div>
</div>
</template>
JavaScript:
let cloneFacility = $($('#facilities_template').html());
$('#facilities_name', cloneFacility).text(value.name);
$('#facilities_name', cloneFacility).attr('data-facility-id', value.id);
$('#collapse', cloneFacility).attr('id','collapse'+ value.id)
$('#facilities_template').before(cloneFacility);
$('#faсility_filter').append(cloneFacility);

Thymeleaf attribute and modal

Edited:
Just figured out that i need JS. Plase, help me with this. I have a th:attr="data-object-id=${department.id}" who store Department id, which i need to put in the modal in the <input id="ids" name="ids" type="text" class="validate">.
How will JS or JQuery looks like? I am trying to write, but all time null or undefined.
<tr th:each="department : ${departments}">
<td class="dep_id" th:text="${department.id}">1</td>
<td th:text="${department.name}"></td>
<td>
<div class="dep_edit">
<a class="settings_dep" th:href="#{'/departments/' + ${department.id} + '/'}"><i class="material-icons">settings</i></a>
<a class="edit_dep modal-trigger" href="#modal3" th:attr="data-object-id=${department.id}"><i
class="material-icons">edit</i></a>
<form method="post" th:action="#{'/departments/' + ${department.id} + '/delete'}" class="inline">
<button type="submit" value="" class="link-button delete_dep">
<i class="material-icons">delete</i>
</button>
</form>
</div>
</td>
</tr>
<div id="modal3" class="modal modal-departments">
<div class="modal-dep modal-content">
<h4>Update Department</h4>
<a href="#" class="dep-modal-close modal-close"><i
class="material-icons icon_close">close</i></a>
<p>Update Department name</p>
</div>
<div class="dep-modal">
<form id="dep-update" class="col s12" th:action="#{'/departments/update'}" method="POST">
<div class="row-modal-dep">
<div class="input-field col s6">
<input id="depName" name="name" type="text" class="validate">
<input id="ids" name="ids" type="text" class="validate">
<label for="name">Department Name</label>
<i class="edit-dep-marker material-icons prefix">mode_edit</i>
</div>
</div>
</form>
<div class="modal-footer">
<input class="modal-close waves-green green btn-dep btn" type="submit" form="dep-update">
</div>
</div>
</div>
I need to give ID value of department to MODAL, so i can update it
My Departments class is easy. Only ID and name;
The 2 tricks to achieve the same (PS - I'm not a Frontend expert):-
1.) Is to create a hidden html-element on your html page & set the value and then get the value of that element using jquery on your modal.
2.) create a function on that html-element and pass the dynamic value to it and then implement your modal hide/show code inside that function, something like this :- -
<a class="edit_dep modal-trigger" th:onclick="'javascript:showFunctionModal(\'' + ${department.id} +'\');'"><i
class="material-icons">edit</i></a>
and your function would be something like this :-
function showFunctionModal(id) {
//logic to hide & show function
}
You can listen to the show.bs.modal event and capture the department id as shown below:
$('#modal3').on('shown.bs.modal', function (e) {
var target = e.relatedTarget;
var departmentId = $(target).data('object-id');
$("#ids").val(departmentId);
});
Problem solved. Huge thanks #Sumit.
th:onclick="'javascript:showFunctionModal(\'' + ${department.id} +'\');'"> on the field which id i want to fetch and then in ready modal function set id.
function showFunctionModal(id) {
$(document).ready(function () {
$('.modal3').modal();
$("#ids").val(id);
});

Jquery does not set text box value

I am trying to set the value of a text box when file upload is selected , how ever it does not happen but I see correct value in alert box.
<div class="row">
<div class="col-xs-2">
<div class="file-label"><i></i>#Resources.FolderPath</div>
</div>
<div class="col-xs-4">
<input class=".form-control" name="fileText" type="text" />
<div class="fileUpload btn btn-primary">
<span>Browse</span>
<input type="file" name="File" id="fileUpload" class="upload"/>
</div>
</div>
<div class="col-xs-4">
<label id="fileSizeError" style="color: red"></label>
</div>
</div>
$(document).ready(function () {
$(document)
.on("change","#fileUpload",
function (e) {
alert($("#fileUpload").val());
$("#fileText").val($("#fileUpload").val());
alert("hi");
});
});
Please help me here.I am using Asp.net MVC as platform.
Your input has a name, but #fileText is an ID selector. Either add an id to it, or use an attribute selector to find it.
So either:
<input class=".form-control" id="fileText" name="fileText" type="text" />
<!-- add id------------------^^^^^^^^^^^^^ -->
or
$("[name=fileText]").val($("#fileUpload").val());
// ^^^^^^^^^^^^^^^---- use attribute selector
Try native js:
document.getElementById("fileText").defaultValue = $("#fileUpload").val();
OR
$("#fileText").attr("value", "some value");
Also;
Check to see if your original code works with replacing .val() with .text

Bootstrap multiple popover display and placement

I have multiple form input and text fields on which I want a popover to display when the field is in focus. Since the content of some of the popovers can be lengthy I don't want to declare the content inside the input tag. Instead I have the following:
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control js-tooltip-trigger" id="name" maxlength="50" >
<div class="js-tooltip" style="display: none;">
<p><strong>Your name.</strong></p>
<p>Enter your full name. This will be used ...</p>
</div>
</div>
<div class="form-group">
<label for="ref">Reference</label>
<input type="text" class="form-control js-tooltip-trigger" id="ref" maxlength="50" >
<div class="js-tooltip" style="display: none;">
<p><strong>Your reference is optional.</strong></p>
<p>Enter a code of your choice for reference purposes.</p>
</div>
</div>
I have the following javascript
$(function () {
$('.js-tooltip-trigger').popover({
html: true,
trigger: 'focus',
content: function () {
return $(correct tool tip).html();
}
});
});
How can I get the correct popover to display or returned in the above javascript. What if I add a data attribute to the tool-tip content to link it to each input field e.g <div class="js-tooltip" style="display:none;" data-tooltip="name"> and then use some jquery to find and return it. How would you do this with jquery? Does anyone have a more elegant solution?
Also how do I get the popover to remain with the input field and auto position upon window resize. Currently it floats away when I resize the window.
Manage to figure it out myself using the above html:
$(function () {
$('.js-tooltip-trigger').popover({
html: true,
trigger: 'focus',
content: function (e) {
return $(this).parent(".form-group").find(".js-tooltip").html();
}
});
});
Can anyone think of a more elegant solution?
You can do like this way...Here is the DEMO
Jquery Part
$(function(){
// Enabling Popover Example 1 - HTML (content and title from html tags of element)
$("[data-toggle=popover]").popover();
// Enabling Popover Example 2 - JS (hidden content and title capturing)
$(".form-control").popover({
html : true,
content: function() {
return $('.js-tooltip').html();
},
title: function() {
return $('.js-tooltip').html();
}
});
});
HTML Part
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control js-popover-trigger" id="name" maxlength="50" data-container="body" data-toggle="popover" data-placement="bottom" data-content="Your name" >
<div class="js-tooltip" style="display: none;" id="n1">
<p><strong>Your name.</strong></p>
<p>Enter your full name. This will be used ...</p>
</div>
</div>
<div class="form-group">
<label for="ref">Reference</label>
<input type="text" class="form-control js-popover-trigger" id="ref" maxlength="50" data-container="body" data-toggle="popover" data-placement="bottom" data-content="Your reference is optional">
<div class="js-tooltip" style="display: none;" id="t2">
<p><strong>Your reference is optional.</strong></p>
<p>Enter a code of your choice for reference purposes.</p>
</div>
</div>
I'm not a fan of how this works, but essentially you have to create an element that stays in the position you want the popover , and append the popover to it. In this case, I have used the container you already have in place for the tooltip html. I'm creating container ID's dynamically so you don't have to worry about doing that in your html.
So for this HTML:
<div class="form-group pos-relative">
<label for="ref">Reference</label>
<input type="text" class="form-control js-tooltip-trigger" id="ref" maxlength="50">
<span class="js-tooltip" style="display: none;">
<p><strong>Your reference is optional.</strong></p>
<p>Enter a code of your choice for reference purposes.</p>
</span>
</div>
This CSS:
.pos-relative{
position:relative;
}
.js-tooltip{
position:absolute;
top:0;
right:0;
}
And this JS--here's where it happens:
$(function () {
$('.js-tooltip-trigger').each(function(ind, ele){
var $ele = $(ele),
$ttSpan = $ele.next('.js-tooltip'),
ttHtml = $ttSpan.html(),
rndID = 'ttid'+ String(Math.random()).substr(2);
// set the ID, strip the style, and empty the html--
// we already have it stored in the var above
$ttSpan.attr('id', rndID).removeAttr('style').html('');
// make the popovers
$ele.popover({
html: true,
trigger: 'focus',
placement: 'right',
container: '#'+rndID,
content: ttHtml
});
});
});
See it in action here

Issues getting CasperJS to upload image to file field - tried CasperJS fill() and PhantomJS uploadFile()

I'm trying to use CasperJS to upload images to a web-form.
My form looks something like this:
<form action="" method="POST" enctype="multipart/form-data" class="form-vertical">
...
<legend>Campaign Banner</legend>
<div class="control-group image-field ">
<label class="control-label">Now Large</label>
<div class="controls">
<div class="file-field"><input id="id_now_large_image" name="now_large_image" type="file"></div>
<div class="image-preview"></div>
<div class="clear"></div>
<span class="help-inline"></span>
</div>
</div>
<div class="control-group image-field ">
<label class="control-label">Now Medium</label>
<div class="controls">
<div class="file-field"><input id="id_now_medium_image" name="now_medium_image" type="file"></div>
<div class="image-preview"></div>
<div class="clear"></div>
<span class="help-inline"></span>
</div>
</div>
<div class="control-group image-field ">
<label class="control-label">Now Small</label>
<div class="controls">
<div class="file-field"><input id="id_thumbnail_image" name="thumbnail_image" type="file"></div>
<div class="image-preview now-small"></div>
<div class="clear"></div>
<span class="help-inline"></span>
</div>
</div>
The submit button looks like this:
<div class="form-actions">
<button type="submit" class="btn btn-small ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false"><span class="ui-button-text">Save changes</span></button>
</div>
I've put a Gist of the full HTML here: https://gist.github.com/victorhooi/8277035
First, I've tried using CasperJS's fill method:
this.fill('form.form-vertical', {
'now_large_image': '/Users/victor/Dropbox/CMT Test Resources/Test Banners/Default Banners/now_large.jpg',
}, false);
this.click(x('//*[#id="content-wrapper"]//button/span'));
I also did a this.capture(), and I saw that the file field had been filled in:
I'm not using the fill method's inbuilt submit, but I'm clicking on the submit button myself:
this.click(x('//*[#id="content-wrapper"]//button/span'));
I then do another capture, and I can see that the form has been submitted:
However, the image doesn't seem to have been uploaded at all.
I've also tried using PhantomJS's uploadFile() method:
this.page.uploadFile('input[name=now_large_image]', '/Users/victor/Dropbox/CMT Test Resources/Test Banners/Default Banners/now_large.jpg');
and then clicking on the submit button as well.
Same issue - the form field gets filled in - however, the image itself doesn't seem to get submitted.
Any ideas on how I can get the images to upload correctly here?
Since you are filling and submitting successfully, try a Wait command on the click.
casper.then(function() {
//+++ form fill here
//waits 1 sec
this.wait(1000, function() {
this.click(x('//*[#id="content-wrapper"]//button/span'));
});
});
Try this.
casper.thenOpen('about:blank', function(){
this.evaluate(function(){
var action = 'upload.php'
var html = '<form action="'+action+'" method="post" enctype="multipart/form-data">'
html += '<input type="file" name="files[]" multiple="multiple">'
html += '<button type="submit">Submit</button>'
html += '</form>'
document.write(html)
})
this.fill('form',{
'files[]': 'file.txt'
}, true)
this.waitFor(function(){
var uri = casper.evaluate(function(){
return document.documentURI
})
if ( 'about:blank' === uri ){
return false
}
return true
})
})

Categories