Ajax debug Error - javascript

i have problem ,when i bind two components (checkbox and label) by adding tag attribute "for" to label , and tag attribute "id" to checkbox, it throws ajax debug error : " Cannot bind a listener for event "click" on element "variantBox4" because the element is not in the DOM".
Here is checkbox code:
AjaxCheckBox checkBox = new AjaxCheckBox("variantBox", variantModel) {
#Override
protected void onUpdate(AjaxRequestTarget target) {
if (variantModel.getObject()) {
target.appendJavaScript(";utils_showElement(" + item.getModelObject().getId() + ");");
} else {
target.appendJavaScript(";utils_hideElement(" + item.getModelObject().getId() + ");");
}
}
};
i add attribute modifier to checkbox in this code:
checkBox.add(new VariantElementAttributeModifier("id",Model.of("checkbox_"+Long.toString(item.getModelObject().getId()))));
here i do the same operation with label:
Label headerLabel = new Label("content", Model.of(item.getModelObject().getContent()));
headerLabel.add(new VariantElementAttributeModifier("for",Model.of("checkbox_"+Long.toString(item.getModelObject().getId()))));
here is html:
<!DOCTYPE html>
<html lang="en" xmlns:wicket="http://maven.apache.org/FML/1.0.1">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<wicket:panel>
<section class="column column_form">
<div class="column__title">Опросный лист</div>
<div wicket:id="container" class="column__content" style="height:
475px;">
<div wicket:id="list" class="form">
<div wicket:id="contentArea"></div>
<div wicket:id="helpLabel"></div>
<wicket:fragment wicket:id="variantFragment"
class="form__item checkbox">
<div class="checkbox__label" wicket:id="content">
</div>
<input class="checkbox__input" type="checkbox"
wicket:id="variantBox" />
<!--<input class="checkbox__input" type="checkbox"
name="input-name" id="checkbox_1"/>-->
<!--<label class="checkbox__label" for="checkbox_1"><b>текст</b><span>текст текст</span><span>текст текст</span></label>-->
</wicket:fragment>
<wicket:fragment wicket:id="Textfragment"
class="form__item form__textfield">
<label wicket:id="textlabel">лейбл</label>
<input type="text" wicket:id="textfield" />
</wicket:fragment>
</div>
</div>
</section>
</wicket:panel>
</body>
</html>
Here is attribute modifier code:
package ru.simplexsoftware.constructorOfDocuments.Utils;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.model.IModel;
public class VariantElementAttributeModifier extends AttributeModifier {
public VariantElementAttributeModifier(String attribute, IModel<?> replaceModel) {
super(attribute, replaceModel);
}
}
Thanks for help.

If you want to manually change the ID of an element, you have to use Component#setMarkupId(String).
Using the AttributeModifier basicly just adds whatever attribute and value you want to the generated HTML. It doesn't tell Wicket about the new ID you want to use though, so Wicket internally still uses its own ID to generate the JavaScript for the AjaxCheckBox.
Btw: If you have an HTML label tag and a corresponding HTML form component, you can also use the wicket:for attribute as in this example:
<label wicket:for="nameInput">Name</label>
<input wicket:id="nameInput">
This tells Wicket which label and form component belong together, so it can generate the correct attributes and values on its own without any extra code in you Java class.

Related

How to best get the parent of parent element in javascript

I'm trying to get the parent of some deeply nested element like below
<div class='content id='cart-content'>
<div class='child1'>
<div class='child1-1'>
<div class='child1-1-1'>
<input
type="checkbox"
class='selectAllItem'
name='selectAllItem'
/> Select All
</div>
</div>
</div>
<div class='child2'>
<div class='child2-2'>
<div class='child2-2-2'>
<input
type="checkbox"
class='selectOneItem'
name='selectOneItem'
/> Select One
</div>
</div>
</div>
</div>
when i check Select All box I want to get the node of the root parent which have id='cart-content'
my approach
1.
let rootNode = event.target.closest('#cart-content')
but the problem is clicking on select one checkbox would also return same result because they both have same root parent and are on same level
approach 2.
let rootNode = event.target.parentNode.parentNode.parentNode.parentNode;
the problem with this approach is the same if i click on select one checkbox would also return the root parent because the distance between the element and the root parent is also 4 parents
Now in jquery i would do the below to get desire result
let rootNode = $(this).parent('.child1-1-1').parents('#');
and when select one is clicked it won't return the rootNode because it doesn't have a direct parent with the class name child1-1-1
How can I achieve this same result using pure javascript vanilla js
Thanks for any help
This is my approach to solve the problem
get the immediate parent of the input field then check if it contails a specific class
var rootParentNode = e.target.parentNode.classList.contains('child1-1-1') ? e.target.closest('#cart-content') : null;
I think you only need to add an unique id to your input dynamically (not hard coding as I do below) and then just do what you want with the parentNode only if your input id is number 1, for instance (Select All) and nothing if it is number 2 (Select One).
Note that the event is listening to changes on check box, not to the checked status
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Static Template</title>
</head>
<body>
<h1>
This is a static template, there is no bundler or bundling involved!
</h1>
<div class="content" id="cart-content">
<div class="child1">
<div class="child1-1">
<div class="child1-1-1">
<input
id="input1"
type="checkbox"
class="selectAllItem selectinput"
name="selectAllItem"
/>
Select All
</div>
</div>
</div>
<div class="child2">
<div class="child2-2">
<div class="child2-2-2">
<input
id="input2"
type="checkbox"
class="selectOneItem selectinput"
name="selectOneItem"
/>
Select One
</div>
</div>
</div>
</div>
</body>
<script>
let allInputs = document.getElementsByClassName("selectinput");
allInputs = [...allInputs];
allInputs.forEach((input) => {
input.addEventListener('change', (e) => {
let parentNode;
if (e.target.id == "input1") {
parentNode = e.target.parentNode.parentNode.parentNode.parentNode;
// Do something with parentNode
console.log(parentNode)
}
else{
// Do something else
}
});
});
</script>
</html>

When changing the element/node style.display, the dom is missing some elements

I have a large DOM with a pre element containing thousands of span nodes with X different name attributes. Upon a user action, I'm changing the style(style.display) X-1 name attributes to none. The node count of unchanged name attribute is over 1000. But after performing this operation, the page is displaying only a couple of hundreds of unchanged instead of all.
Note: I don't see any issue when node count is low.
function filters() {
var nameElement = document.getElementsByName('filterType');
let selectedFiltersList = [];
if (nameElement.length > 0) {
for (let i = 0; i < nameElement.length; i++) {
if (nameElement[i].checked) {
selectedFiltersList.push(nameElement[i].defaultValue);
}
}
}
if (selectedFiltersList.length > 0) {
const allFilters = ["Warning", "Error", "State"];
const unSelectedFilters = allFilters.filter(
val => !selectedFiltersList.includes(val),
);
unSelectedFilters.forEach(name => {
let nameArray = document.getElementsByName(name);
if (
nameArray &&
nameArray.length > 0 &&
nameArray[0].style.display !== 'none'
) {
nameArray.forEach(elem => (elem.style.display = 'none'));
}
});
}
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<title>Viewer</title>
<link rel="stylesheet" href="../css/view.css" />
</head>
<body>
<div class="header">
<div class="filters" onclick="filters()">
<input type="checkbox" name="filterType" value="Warning" />
Warning
<input type="checkbox" name="filterType" value="Severe" />
Severe
<input type="checkbox" name="filterType" value="State" /> State
</div>
</div>
<div class="output">
<pre id="data">
<span class="st" name="State">X State ===> hello state
</span>
<span class="wrn" name="Warning">X Warn ===> hello warn
</span>
<span class="err" name="Error">X Error ===> hello error
</span>
....(// thousands of span elements like above)
</pre>
</div>
</body>
</html>
As #Mike Kamermans already commented: you should work with a class (here hide) to make targeted spans invisible. The name-attribute cannot be assigned to spans but you can use data-name instead.
Your markuo structure is still somewhat "unorthodox". I expect you will not be using <span>s in a <pre> in the finished version of the page, but the principle can be demonstrated here nonetheless.
in flt I collect the values of all checked boxes. I then loop (forEach) over all #data spans and toggle() their class hide by checking if their dataset.name can be found in flt: if they cannot be found I "hide" the element, otherwise I remove the class "hide" again.
function filters() {
let flt=[...document.querySelectorAll('[name=filterType]:checked')].map(f=>f.value);
[...document.querySelectorAll('#data span')].forEach(s=>
s.classList.toggle('hide',!flt.includes(s.dataset.name)));
}
.hide {display:none}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<title>Viewer</title>
<link rel="stylesheet" href="../css/view.css" />
</head>
<body>
<div class="header">
<div class="filters" onclick="filters()">
<label><input type="checkbox" name="filterType" value="Warning" checked/>
Warning</label>
<label><input type="checkbox" name="filterType" value="Severe" checked/>
Severe</label>
<label><input type="checkbox" name="filterType" value="State" checked/> State</label>
</div>
</div>
<div class="output">
<pre id="data"><span class="st" data-name="State">X State ===> hello state
</span>
<span class="wrn" data-name="Warning">X Warn ===> hello warn
</span>
<span class="err" data-name="Severe">X Error ===> hello error
</span>
....(// thousands of span elements like above)
</pre>
</div>
</body>
</html>
( I adjusted some of your span-(data-)names so they correspond with the three checkbox
values. )

How to add dynamic input fields and corresponding radio using AngularJS

Hi I have a html file and an AngularJS file (Bootstrap ui). Whenever I click on add button it should help me create a new td (input field) and 3 corresponding radio buttons as well. The following is my code but not sure how to implement that. I have tried to replace div with tr and td both doesn't work.
Html:
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.3.js"></script>
<script src="static/js/app.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="AlertDemoCtrl">
<alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</alert>
<button type="button" class='btn btn-default' ng-click="addAlert()">Add Alert</button>
</div>
</body>
</html>
and JS file:
angular.module('ui.bootstrap.demo').controller('AlertDemoCtrl', function ($scope) {
$scope.alerts = [
{ type: 'danger', msg: 'Oh snap! Change a few things up and try submitting again.' },
{ type: 'success', msg: 'Well done! You successfully read this important alert message.' }
];
$scope.addAlert = function() {
$scope.alerts.push({msg: 'Another alert!'});
};
$scope.closeAlert = function(index) {
$scope.alerts.splice(index, 1);
};
Please anyone can help. Thanks in advance.
The basic approach of AngularJs is:
Template generated HTML, driven from values in your data model
Use of custom directives, rather than jQuery, if you want to dynamically
manipulate the DOM.
In your case, a simple ng-repeat loop ought to suffice, generating a td and three inputs for each element of a collection/array in your data model. When you click the button, you should update the number of elements in the collection. If necessary, you can force a UI update with $apply.
Something like:
<tr ng-repeat="cell in cells">
<td>
<label><input type="radio" ng-model="cell.value1" value="1">1</label<br/>
<label><input type="radio" ng-model="cell.value2" value="2">2</label<br/>
<label><input type="radio" ng-model="cell.value3" value="3">3</label<br/>
</td>
</tr>

Clearing input text field value with Jquery

I seem to be able to hide the resource container using
resource.parent().parent().hide();
but I don't understand why the input value is not clearing with
resource.parent().siblings('.resource-value').children('input').val('');
when I use
resource.parent().siblings('.resource-value') I get the parent of the input value but adding .children('input').val('') on top of that does nothing or if I add .children('input:text').val('')
I have very similar code for something else which works just fine, looked at other questions and not sure what I'm missing.
function removeResource(resource) {
'use strict';
//hide resource on screen
resource.parent().parent().hide();
//set resource text value to ''
resource.parent().siblings('.resource-value').children('input').val('');
}
(function($) {
'use strict';
$(function() {
$('#resources').on('click', '.remove-resource', function(evt) {
// Stop the anchor's default behavior
evt.preventDefault();
// Remove the image, toggle the anchors
removeResource($(this));
});
});
})(jQuery);
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div id="resources">
<div class="resource">
<div class="resource-value">
<input type="text" name="resources[]" value="1" />
</div>
<p class="hide-if-no-js"><a title="remove resource" href="javascript:;" class="remove-resource">remove resource</a > </p>
<!-- .hide-if-no-js -->
</div>
<div class="resource">
<div class="resource-value">
<input type="text" name="resources[]" value="2"/>
</div>
<p class="hide-if-no-js"><a title="remove resourcee" href="javascript:;" class="remove-resource">remove resource</a> </p>
<!-- .hide-if-no-js -->
</div>
</div>
</body>
<html/>
Tried your code and worked fine for me in terms of the actual value of the field clearing, though in inspector the HTML element still has the value attribute showing.
You can use
.attr('value','')
to clear that too http://jsfiddle.net/bvtg93dm
You just have to change the value witch jquery to set "" (so, empty).
input.attr('value','')
Try to log your sibling element with
Try to change your removeResource function to
function removeResource(resource) {
'use strict';
//hide resource on screen
var parent = resource.parent().parent();
parent.hide();
// log your element
console.log(parent.find('.resource-value input'));
// make sure you are getting an element you need
console.log(parent.siblings('.resource-value').childer('input').get(0);
//set resource text value to ''
parent.find('.resource-value input').val('');
}

.toggle() sometimes taking double click before working

I have a simple application, where I'd like to toggle between showing and hiding elements in a fieldset using jQuery's .toggle effect. The trouble is, occasionally I have to double-click the button that enables the toggle, to get it to work.
Any ideas on what's going on?
HTML:
<!DOCTYPE html>
<html>
<head>
<script src="jquery-2.1.1.min.js"></script>
<script src="test.js"></script>
</head>
<body>
<div class="LeftFrame">
<div id="LeftTable"><strong>Left</div>
</div>
<div id="MainTable"><strong>Main
<div>
<br>
<form><fieldset><legend><button id="buttonShowFields">Add Info</button></legend>
<div id="InfoAddFields">
ID: <input type="text"><br>
Serial Number: <input type="text"><br>
Location: <select id="inputLocation">
<option>Location1</option>
<option>Location2</option></select><br>
Status: <select id="inputStatus">
<option>Complete</option>
<option>In Process</option></select><br>
</div>
</fieldset></form>
</div>
</div>
</body>
</html>
... and javascript (test.js ref in html above):
$(document).ready(function(){
// Show options to add workorder
// $("#WOAddFields").hide();
$("#buttonShowFields").click(function(){
$("#InfoAddFields").toggle();
});
});
Prevent the submit with event.preventDefault() when you click the button
http://jsfiddle.net/3NPPP/
$(document).ready(function(){
$("#buttonShowFields").click(function(e){
e.preventDefault();
$("#InfoAddFields").toggle();
});
});
I was having the same problem when using plain javaScript to toggle an element with the following function:
function toggle(element){
if (element.style.display !== "none")
element.style.display = "none";
else element.style.display = "block";
}
I noticed that when I added display:none to the CSS of the element I wanted to toggle, I needed to double click to first show the element. To fix this, I had to explicitly add style="display:none" to the HTML element tag.
instead of this...
<button id="buttonShowFields">Add Info</button>
use this...
<input type="button" id="buttonShowFields" value="Add Info" />
Please change event method to bind instead click.
$("#buttonShowFields").bind('click',function(){
$("#InfoAddFields").toggle();
});

Categories