Using attr binding in knockout with a boolean attribute 'autofocus' - html

For some attributes, it is the presence of the attribute that has an effect - the value that is assigned to it is irrelevant. For example, the autofocus attribute can be set to 'false' or 'true, or 'banana' and the element is still gets automatically focused. IE, the following are all equivalent and cause the div to get focus :
<div autofocus="false" contenteditable="true"></div>
<div autofocus="true" contenteditable="true"></div>
<div autofocus="banana" contenteditable="true"></div>
Knockout has an 'attr' binding, but it seems to be only useful for assigning values to attributes, not for adding/removing attributes.
Is there another way to do it in knockout, or am I forced to set it from javascript?
NB Using chrome on ubuntu.

Use a boolean false value to remove the attribute, use a string 'false' to set the attribute. What more do you need?
eg:
// Set as boolean, removes the attribute
autofocus(false);
// Set as boolean, adds the attribute
autofocus(true);
// Set as string, adds the attribute
autofocus('false');
// Set as string, adds the attribute
autofocus('true');
See here for an example: http://jsfiddle.net/badsyntax/XMDFh/

You can use hasfocus knockout binding:
<input data-bind="hasfocus: isSelected" />
Read more here: http://knockoutjs.com/documentation/hasfocus-binding.html

You can write a kohandler that removes attributes using jquery.

There is not a native binding in Knockout to add or remove an attribute, only to set an attribute.
The reason why the hasFocus binding exhibits the behavior it does is because it uses an element's native .focus() and .blur() methods to add or remove focus.
Knockout having difficulty managing non-boolean attributes has been reported before, here's one example where Michael Best mentioned it would not be addressed:
https://github.com/SteveSanderson/knockout/issues/391
Update:
You could create a binding handler along these lines:
ko.bindingHandlers.toggleAttr = {
update: function (element, valueAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor());
var attr = ko.utils.unwrapObservable(options.attr);
var param = ko.utils.unwrapObservable(options.param);
param ? element.setAttribute(attr, true) : element.removeAttribute(attr);
}
};
Which would allow you to do this:
<input data-bind="toggleAttr: { attr: 'autofocus', param: focusMe }" />
Here's a fiddle: http://jsfiddle.net/nathanjones/9EzBD/

Related

How can I change the html img element source witch dart?

I have this img element in my HTML project:
<img id="themeToggle" src="./images/moon.svg">
and i want to change the source of this element to be "./images/sun.svg".
I tried with:
void main() {
var themeToggleButton = querySelector('#themeToggle');
themeToggleButton?.onClick.listen((event) {
themeToggleButton.dataset['src'] = './images/sun.svg';
});
}
since the .dataset attribute is the only one that lets you to access the selected element's attributes, but it does not work. Any suggestion, please?
You should be able to use the .attributes getter to get the attributes Map and set there the value:
themeToggleButton?.attributes['src'] = './images/sun.svg'
Note: .dataset (as specified in the docs) is used only for the element properties that start with data-

Conditionally adding tags options parameter to select2

I have multiple elements on a page that are triggering a load of select2 to the element. I'm trying to conditionally check if the element has a certain class, and if so add the tag option; otherwise do not. I thought something like this would work, but it's not:
$('.element_to_add_select_two_on').select2({
tags:function(element) {
return (element.className === 'classname_i_am_targeting');
},
});
What am I missing here? I'm subjecting myself to the following buffoonery to get this to target and load:
$('.element_to_add_select_two_on').each((index,element) => {
let showTags = false;
if ($(element).attr('class').split(' ').includes('classname_i_am_targeting')) {
showTags = true;
}
$(element).select2({
tags:showTags,
});
});
There are a few problems with your first attempt. First, you are defining tags as a function when what you want is the result of the function, since tags needs to be defined as a boolean true or false. The other is that inside your .select2() call, you do not have access to the calling element $('.element_to_add_select_two_on') in the way that you think. It isn't an event that you are listening on, it's a function call that wants an object passed with its configuration.
You conveyed that your second method works, but it can be simplified with the jQuery hasClass() function:
$('.element_to_add_select_two_on').each((index, element) => {
$(element).select2({
tags: $(element).hasClass('classname_i_am_targeting'),
});
});
There is a much simpler way to do all of this, however, and it is much more flexible and already built into select2 via the way of data-* attributes (note, you need jQuery > 1.x). You can simply add data-tags="true" to any of your select elements with which you want tags enabled. These will override any configuration options used when initializing select2 as well as any defaults:
<select data-tags="true">
...
</select>

Angular v6 Elements #Input() For Initial Binding Not Working

I have created a custom element and placed on a page like this:
<my-custom-element [value]="100"></my-custom-element>
In the component definition, I have this:
#Input() value: number = 50;
At run-time, the value is always 50. I expect it to be 100. If I remove the default, value is undefined. What am I missing?
Thanks!!
In NG Elements you may not find in your OnIt but in OnChanges.
Please add below line and check it is defined.
public ngOnChanges(): void {
console.log('on changes value: ', this.value);
}
You can set data using HTML attributes and to change/update data in Angular Elements you have to use vanilla js, query selector and assign data like below
custom element tag with initial value = 0
<my-custom-element value="0" ></my-custom-element>
select custom element through the query selector and assign value.
var customElement = document.querySelector('my-custom-element');
customElement.value = 100;

"contenteditable" attribute doesn't work when element added via "[innerHTML]" in Angular

I have met an unexpected behavior for me of contenteditable attribute in Angular. I have an object with HTML, stored as a value:
public json_html = {
"button1":"<p contenteditable='true'>first section</p>",
"button2":"<p>second section</p>",
"button3":"<p>third section</p>",
}
And I apply this values like this (via innerHTML):
<div [innerHTML]="selectedButton"></div>
Everything works fine except contenteditable attribute - it's just missed in HTML:
QUESTION:
How to force contenteditable attribute to work (when element becomes through [innerHTML])? Is there a proper way to do that or may be there is a workaround?
LIVE EXAMPLE: https://stackblitz.com/edit/angular-9pyhg3-lnivvj?file=app%2Fbutton-overview-example.html
That attribute is stripped for security reasons
If you tell Angular that it should treat it as safe, use DomSanitizer
constructor(sanitizer: DomSanitizer) {
this.json_html = {
"button1": sanitizer.bypassSecurityTrustHtml("<p contenteditable='true'>first section</p>"),
"button2":"<p>second section</p>",
"button3":"<p>third section</p>",
}
StackBlitz example

Adding properties for a Polymer element to observe based on content or a better way to handle forms

I need to create a form using the Polymer Paper-Input elements, and I need a way to know when all required content has been filled out.
I looked for a built in element, but didn't see one. So I wanted to create a polymer form element that would wrap all of the input tags. The resulting element would have an Invalid attribute which lets you know if any of the input tags are invalid.
The use of the tag would look like this:
<test-form id="testform">
<paper-input label="test" required error="This field is required"></paper-input>
</test-form>
Invalid: {{ $.testform.invalid }}
However, it appears that by the time in the elements lifecycle that I can loop over all the elements inside of the content tag, that anything added to the observe object is ignored.
Here is the code I was working on below:
<polymer-element name="test-form" attributes="invalid">
<template>
<content id="content">
</content>
</template>
<script>
Polymer('test-form', {
domReady: function () {
this.observe = {};
for (var i = 0; i < this.children.length; i++) {
this.observe["this.children[" + i + "].invalid"] = "valChanged";
}
},
invalid: false,
valChanged: function (oldValue, newValue) {
// TODO: If newValue is true set invalid to true
// If newValue is false, loop over all elements to see if all are now valid and invalid can be set to false.
alert("VALUE CHANGED" + oldValue + newValue);
}
});
</script>
Is there a better way to handle this or does anyone know how to make changes to what polymer is observing at this point in the lifecycle?
As far as checking the form's validity, you could simply check each form element's invalid property:
validate: function() {
var invalid = false;
Array.prototype.forEach.call(this.children, function(child) {
if (child.invalid === true) {
invalid = true;
}
});
this.invalid = invalid;
}
Then you could add an input event listener and run this method each time a form element's input changes.
Here's a working jsbin.
If I understand your question, your high level goal is form validation?
As has been detailed in polycasts and other places, I have used iron-form which has some very powerful validate() functionality, including what you mention above and much more.
It does sometimes require some odd usages of hidden <input> fields to get all of the work done, but this is easy to learn in the polycasts, such as polycast 55 and 56
If you stumbled upon this question in 2017, you would definitely now want to use more primitive tech, after you've seen what this has to offer.