In my code i have two grid on for base layer other for utility layer .
Base layer has radio button and on clicking the logic used is working
{
var baseLayerGroup= new ol.layer.Group({
layers:[
openstreetmapstandard,openstreetmaphumanitarian
]
})
map.addLayer(baseLayerGroup);
//Layer Switcher Logic for Baselayer
var baseLayerElements = document.querySelectorAll('.sidebar1 > input[type=radio]');
for(let baseLayerElement of baseLayerElements){
baseLayerElement.addEventListener('change',function(){
let baseLayerElementValue = this.value;
baseLayerGroup.getLayers().forEach(function(element, index, array){
let baseLayerTitle = element.get('title');
element.setVisible(baseLayerTitle === baseLayerElementValue);
})
})
}
var dataLayerGroup= new ol.layer.Group({
layers:[
Sector_office,Roads
]
})
and my logic for checkbox is :
Sector_office.setVisible(true);
Roads.setVisible(false);
var toggleLayer = function(inputEl){
map.getLayers().forEach(function(layer){
if (layer.get('name') === inputEl.name)
layer.setVisible(inputEl.checked);
});
};
map.addLayer(dataLayerGroup);
but my checkbox logic is not working and here is my html page for it
<input type="checkbox" onClick="toggleLayer(this);" value="Sector_office" checked>Sector office<br>
<input type="checkbox" onClick="toggleLayer(this);" value="Roads" checked>Roads<br>
</div>
For what I see you have a couple of issues in your code.
In the handler function you are referencing the name attribute of the dom element, but I see not such attribute in the html. That will always result false. So you have to set the name attribute or use the value attribute.
The onclick event handler receive as a parameter a MouseEvent argument. To get a reference of the dom element inside the handler you can use this or you can use the event argument attribute target.
Resuming,
handler
const toggleLayer = function(e){
const chk = e.target.
map.getLayers().forEach(function(layer){
if (layer.get('name') === chk.value)
layer.setVisible(chk.checked);
});
};
html
<input type="checkbox" onclick="toggleLayer(event)"
value="Sector_office" checked>Sector office<br>
<input type="checkbox" onclick="toggleLayer(event)"
value="Roads" checked>Roads<br>
Related
<section key={i}>
<input
type='radio'
key={attribute.name + item.id}
id={attribute.name + item.id}
name={attribute.name}
value={item.value}
defaultChecked={i === 0}
onClick={(event) => inputClick(attribute, event)}
/>
<label
htmlFor={attribute.name + item.id}
>
{
item.value
}
</label>
</section>
The code above is more or less what a .map() function is supposed to return in my React.js APP, creating input radio buttons for customizing a product before adding it to the cart state. All I did was remove some classes, etc. that were there for CSS purposes, etc.
Ideally, what is supposed to happen here is that...
When rendering the product page for the first time, the very first input radio button that is returned by .map() should be checked by default. This works thanks to the "defaultChecked" attribute. No problems here.
After I click a different input radio button (not the "defaultChecked" one), the checked input should change and all the other inputs should be left unchecked. As I understand it, input radio buttons with the same 'name' attribute do this automatically.
When clicking the input radio button, the "onClick" function should trigger. This is where the code is not functioning as I wish it would.
The issue is that when my page renders for the first time and I click on an input radio button (other than the "defaultChecked") the "onClick" function does not trigger. It only triggers when I have clicked on a different input once and then on another.
A.k.a. it triggers on the second click. After that second click, it works as intended - every time a different input radio button is selected/clicked on - the function triggers, but not for the very first time.
I tested this with console.log("I am triggered") at the end of the "onClick" "inputClick(attribute, event)" function, and only on the second click would the console log "I am triggered".
I was able to fix the issue by removing the "defaultChecked" attribute. I think the issue might be tied to the fact that the "onClick" function is only able to be triggered when one input gains the "checked" attribute and another loses it, but the "defaultChecked" attribute does not count as an input being "fully checked" or something like that.
I could leave it at that, but the project that I am working on required me to have a default checked input radio button on the first-page render. So, I can't just delete the "defaultChecked" attribute and call it a day.
Any ideas on what could be causing this behavior?
UPDATE1
The following is the body of the inputclick() function:
//* Handle input selection
const inputClick = (attribute, event) => {
//* Parse state
let state = JSON.parse(JSON.stringify(itemState));
//* Get all the required values from the clicked input
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Check if the attribute is in state
const attributeIs = state.some(item => item.id === attributeId);
//* If the attribute does not exsist - add the attribute to state
if(attributeIs === false) {
const obj = {
id: attributeId,
selectedItem: itemTargetValue
};
state.push(obj);
return setitemState(state);
}
//* If the attribute id already exsists in state
if(attributeIs) {
//* Find the index of the attribute in question
const attributeIndex = state.map(object => object.id).indexOf(attributeId);
const attributeInQuestion = state[attributeIndex].selectedItem;
//* If the attribute's item's id is the same as the seelected input - do nothing
if(attributeInQuestion === itemTargetValue) {
return
}
//* If the attribute's item's id is not the same - change it to the new value
if(attributeInQuestion !== itemTargetValue) {
state[attributeIndex].selectedItem = itemTargetValue;
console.log(state);
return setitemState(state);
}
}
};
Here is the working code that fixes the issue.
Yes, there is some streamlining, for example, code shortening, etc. Yet, the difference that solves the issue is that...
The code that I had posted in the question originally was working. Meaning, that it was firing the inputClick() function and changing which input was selected, the problem was that...
...the defaultChecked logic in the was preventing the chosen input from being rendered as a selected input a.k.a. to change its CSS styling.
Bellow is the new onClick() function.
//* Handle input selection
const inputClick = (product, attribute, event) => {
let newCart = JSON.parse(JSON.stringify(cartState));
const productId = product.id;
const attributeId = attribute.id;
const itemTargetValue = event.target.value;
//* Find the product in cart state */
const productIndex = newCart.map((object) => object.id).indexOf(productId);
//* Find the attribute by id in question */
const attributeIndex = newCart[productIndex].selectedAttributes.map(object => object.id).indexOf(attributeId);
//* Change the products selected attribute item */
newCart[productIndex].selectedAttributes[attributeIndex].selectedItem = itemTargetValue;
setcartState(newCart);
};
Below is what the "inside" of the looks like now.
<input
type='radio'
key={product.id + attribute.name + item.id}
id={product.id + attribute.name + item.id}
name={product.id + attribute.name}
value={item.value}
defaultChecked={product.selectedAttributes[selectedId].selectedItem === item.value}
onChange={(event) => inputClick(product, attribute, event)}
>
</input>
I was trying to test a few novice tricks from a project tutorial. Wanted to create a small scale task app and ran into a weird problem. The last document.addEventListener below should theoretically call the closest element with the class name of ".name" should be detected since its in the same parent div with the button. However it is returning NULL. Am I applying the .closest() method wrong?
The event listener detects the button after everytime a task is created. Not sure why it returns NULL when, after creating the task via addTaskButton, the task with the class name of ".name". I even tried to create a data attribute id based off of the taskName itself to see if it'll detect, but still NULL / erroring.
const list = []
const container = document.querySelector('.container');
const itemContainer = document.querySelector('.item');
const addTaskButton = document.querySelector('.add-task');
const taskInput = document.querySelector('#task-name');
function renderTasks(){
itemContainer.innerHTML = ''
list.forEach(task => {
const itemElement = document.createElement('div')
itemElement.innerHTML = `
<div class="name">
${task.taskName}
</div>
<button class="retrieval">Retrieve ID</button>
`
itemElement.dataset.itemName = task.taskName
itemContainer.appendChild(itemElement);
})
}
addTaskButton.addEventListener('click', (e)=>{
e.preventDefault();
list.push({ taskName: taskInput.value})
renderTasks()
})
document.addEventListener('click', (e)=>{
if(e.target.matches('.retrieval')){
const taskName = e.target.closest('.name');
console.log(taskName)
}
})
Ok, I double checked the mdn article it says:
closestElement is the Element which is the closest ancestor of the
selected element. It may be null.
That means it only looks for parents and parents of parents and so on, not 'siblings'.
I am trying to wrap an input field inside a custom element.
The custom element DOM looks like this:
<custom-element>
<div class="fancy-wrapper">
<input value="4">
</div>
<custom-element>
While the element should work like this:
<custom-input id="test"></custom-input>
<script>
let test = document.getElementById('test')
console.log(test.value); // should return 4 (value of inner input)
test.onkeydown = function(e){
console.log(e.target.value); // should the new value of the inner input
};
</script>
Is there any way to get the <custom-input> attributes redirected to the <input> attributes inside it, without connecting everything by hand?
No, it is no different than having one DIV and another child DIV
You have to make the connection between the CustomElement and content yourself.
One way is to define a Get/Set function on your Custom-Element that fetches the value of a child input
Instead of manually declaring Get/Set You can ofcourse loop any child element and assign on the CustomElement with defineProperty or Proxies
Example below creates 2 INPUT fields and a this.input array:
<number-and-range>
<input type="number"> // this.input[0]
<input type="range"> // this.input[1]
</number-and-range>
And connects (GET/SET) <number-and.range>.value to this.input[0]
customElements.define('number-and-range', class extends HTMLElement {
get value() {
return this.input[0].value;
}
set value(val) {
//input validation should go here
this.input[0].value = val;
console.clear();
console.log('new value:',val);
}
connectedCallback() {
this.input = ['number', 'range'] //create [0] and [1] values in array
.map((type, idx) => Object.assign(
this.appendChild(document.createElement('input')), {
type,
min: 20,
max: 50,
oninput: _ => this.value = this.input[~~!idx].value = this.input[idx].value //toggle [0] and [1]
}));
this.value = 42;//default value
}
});
let el=document.querySelector('number-and-range');
console.log(el.value);
el.value=99;
<body>
<h3>Custom Element : Connected INPUT and Range slider</h3>
Please enter a number between 20 and 50, or use the range slider
<p>
<number-and-range></number-and-range>
</p>
</body>
If I understood your question, you want to copy all the attributes of the custom-element to the input tag.
What you can do is,
//get all attributes of custom element
var el = document.getElementById ('test');
// get all attributes
var attrs = el.getAttributeNames(); // returns an array
// loop over attrs array and append the attribute and value in the input,
// I am assuming, you will not add copy id attribute here.
var input = el.getElementsByTagName ('input')[0];
for (var index = 0; index < attrs.length; index++) {
if (attrs[index] !== 'id') {
// set attribute of input with attribute name from the array,
// and get the value from from input.
input.setAttribute (attrs[index], el.getAttribute (attrs[index]));
}
}
It's an idea, you can do something else.
HTML:
<custom-element id="test">
<div><input value="43" /></div>
</custom-element>
JavaScript:
class CustomElement extends HTMLElement {
constructor() {
super();
const currentDocument = document.currentScript.ownerDocument;
this.template = currentDocument.querySelector('input');
}
get value() {
return this.template.getAttribute('value');
}
set onkeydown(cb) {
return this.template.addEventListener('keydown', cb);
}
}
window.customElements.define('custom-element', CustomElement);
let test = document.getElementById('test');
console.log(test.value);
test.onkeydown = function(e) {
console.log(e.target.value);
};
Can take a look at demo
You can append to the innerHTML of the custom element tag
var string="<input type='text' ";
document.getElementById('test').onclick = function(e){
var attr=[...document.querySelector('#test').attributes].map(attr => attr.nodeName);
attr.forEach((e)=>{
var val=document.getElementById('test').getAttribute(e);
string+=e+"="+val + " ";
})
document.getElementById("test").innerHTML+=string + '//>' ;
console.log(document.getElementById("test").outerHTML)
};
<custom-input id="test">dd</custom-input>
I am working on Dojo Version 1.8.I have designed one custom widget as below. Its a snippet
<div>
<div>
<input
id ="NZ1",
data-dojo-attch-point = "NZ1"
data-dojo-attch-type = "ecm.widget.ValidationTextBox"
data-dojo-attch-event = "onBlur : makeAllSmall"
/>
</div>
<div>
<input
id ="NZ2",
data-dojo-attch-point = "NZ2"
data-dojo-attch-type = "ecm.widget.ValidationTextBox"
data-dojo-attch-event = "onBlur: makeAllSmall"
/>
</div>
</div>
Here is event handler
makeAllSmall : function(evt){
var currVal=evt.target.value;
currVal = currVal.toLowerCase();
/**Some Other business logic on currVal **/
}
This evt is always coming as undefined . I am quite new to Dojo. Am I missing something in HTML side ? I tried to change HTML as below but not luck
<input
id ="NZ2",
data-dojo-attch-point = "NZ2"
data-dojo-attch-type = "ecm.widget.ValidationTextBox"
data-dojo-attch-event = "onBlur : makeAllSmall"
data-dojo-args="e"
/>
First thing first, is there a typo in the method "onBlurr"? I see there is an extra 'r'. Shouldn't it be "onBlur"?
If you look at the DOJO API documentation for onBlur event, it doesn't pass an event object like what you are expecting
onBlur()
Defined by: dijit/_FocusMixin
Called when the widget stops being "active" because focus moved to something outside of it, or the user clicked somewhere outside of it, or the widget was hidden.
Examples
Example 1
var btn = new Button();
// when /my/topic is published, this button changes its label to
// be the parameter of the topic.
btn.subscribe("/my/topic", function(v){
this.set("label", v);
});
Next, in your event handler, you are trying to change the text to lowerCase and this can be done like
makeAllSmall : function(){
var currVal=this.get("value");
currVal = currVal.toLowerCase();
/**Some Other business logic on currVal **/
}
Another way of doing this without the event handler is to force the ValidationTextBox to convert everything to lowercase using construction parameters like
<input
id ="NZ2",
data-dojo-attach-point = "NZ2"
data-dojo-attach-type = "ecm.widget.ValidationTextBox"
data-dojo-props='lowercase:true'
data-dojo-attach-event = "onBlurr : makeAllSmall"
/>
Note that I have added data-dojo-props='lowercase:true'
Hope this helps.
You should be able to attach a DOM event to your custom widget by:
Using data attribute data-dojo-attach-event in the markup.
And using _AttachMixin passing your callBack function.
Example:
<div id="somenode"><span data-dojo-attach-point="anattachpoint"
data-dojo-attach-event="click: clicked">Click me</span></div>
var MyDijit = declare([ _WidgetBase, _AttachMixin ], {
// .. declaration goes here ..
clicked: function(e) {
// handle event
}
});
// instantiate the dijit instance, which will attach to the 'somenode' div.
var mydijit = new MyDijit({}, dom.byId('somenode'));
mydijit.startup();
How can I set focus on an input by (click) event? I have this function in place but I'm clearly missing something (angular newbie here)
sTbState: string = 'invisible';
private element: ElementRef;
toggleSt() {
this.sTbState = (this.sTbState === 'invisible' ? 'visible' : 'invisible');
if (this.sTbState === 'visible') {
(this.element.nativeElement).find('#mobileSearch').focus();
}
}
You can use the #ViewChild decorator for this. Documentation is at https://angular.io/api/core/ViewChild.
Here's a working plnkr: http://plnkr.co/edit/KvUmkuVBVbtL1AxFvU3F
This gist of the code comes down to, giving a name to your input element and wiring up a click event in your template.
<input #myInput />
<button (click)="focusInput()">Click</button>
In your component, implement #ViewChild or #ViewChildren to search for the element(s), then implement the click handler to perform the function you need.
export class App implements AfterViewInit {
#ViewChild("myInput") inputEl: ElementRef;
focusInput() {
this.inputEl.nativeElement.focus()
}
Now, click on the button and then the blinking caret will appear inside the input field. Use of ElementRef is not recommended as a security risk,
like XSS attacks (https://angular.io/api/core/ElementRef) and because it results in less-portable components.
Also beware that, the inputEl variable will be first available, when ngAfterViewInit event fires.
Get input element as native elements in ts file.
//HTML CODE
<input #focusTrg />
<button (click)="onSetFocus()">Set Focus</button>
//TS CODE
#ViewChild("focusTrg") trgFocusEl: ElementRef;
onSetFocus() {
setTimeout(()=>{
this.trgFocusEl.nativeElement.focus();
},100);
}
we need to put this.trgFocusEl.nativeElement.focus(); in setTimeout() then it'll work fine otherwise it will throw undefined error.
try this :
in you HTML file:
<button type="button" (click)="toggleSt($event, toFocus)">Focus</button>
<!-- Input to focus -->
<input #toFocus>
in your ts File :
sTbState: string = 'invisible';
toggleSt(e, el) {
this.sTbState = (this.sTbState === 'invisible' ? 'visible' : 'invisible');
if (this.sTbState === 'visible') {
el.focus();
}
}
try this.
//on .html file
<button (click)=keyDownFunction($event)>click me</button>
// on .ts file
// navigate to form elements automatically.
keyDownFunction(event) {
// specify the range of elements to navigate
let maxElement = 4;
if (event.keyCode === 13) {
// specify first the parent of container of elements
let container = document.getElementsByClassName("myForm")[0];
// get the last index from the current element.
let lastIndex = event.srcElement.tabIndex ;
for (let i=0; i<maxElement; i++) {
// element name must not equal to itself during loop.
if (container[i].id !== event.srcElement.id &&
lastIndex < i) {
lastIndex = i;
const tmp = document.getElementById(container[i].id);
(tmp as HTMLInputElement).select();
tmp.focus();
event.preventDefault();
return true;
}
}
}
}