I can't find any method in the Documentation to manually set the focus to an element.
It is supposed to support the DOM Element class, but when i do
var elem = ele.ownerDocument.getElementById("start");
elem.focus();
it does nothing. elem is correctly set, but it doesn't recognize the focus() method.
Apple's TVJS Framework doesn't provide any method in his classes to manually focus an element.
Neither in the standard Document Object Module classes it incorporates have any kind of method to directly access the DOM and focus an element.
The closes thing available is the autoHighlight attribute which allows to focus on render some specific elements in certain positions.
In pure js you can document.getElementById("start").autofocus; : On page load input is autofocus
Use autoHighlight for this purpose.
autoHightlight="true"
Both the containing element and one child element have to be set to true.
Related
EDIT: So it seems to be an issue with selectors? Does jqLite not support selectors or some reduced version of them?
find('input') and find('button') will return results but if I try to filter it with a ":first" or something then it returns no results.
I can't seem to get jqLite's find() to return any child inputs of my div.
I have a $watch on a boolean function that my ng-show uses. So when this div becomes visible I want to apply focus on the div element and then find the first input descendant and focus on that.
example div element that the directive watches:
<div myDirective="function()">
text and stuff
<button>
<another button>
</div>
<div myDirective="function()">
<input>
</div>
this is my helper function in my directive:
function highlightAndFocus(node) {
// focus the div
node.focus();
// get angular's jqlite wrapped element
var task = angular.element(node);
task.addClass('highlight');
// these return empty statements
console.log(task.find('input:first'));
console.log(task.find('button:visible:not("#cancel"):first'));
}
The angular documentation says it finds only by tag name but isn't that what "input" and "button" are?
https://docs.angularjs.org/api/ng/function/angular.element
What's going on here? It seems silly to include jquery just for this one usecase when it seems like it should be supported. I'm printing the var task and I can see the input child elements in the web console.
JQlite is not the same thing as jQuery. If jQuery is available on the page, Angular will use it, but if it isn't, jQlite is used instead.
The docs clearly say that jQlite's .find() only supports lookup by tag names, it doesn't to work with additional selectors (like :first).
You can use the standard DOM APIs instead, namely Element.querySelectorAll(), if you really need it.
Right now, I'm binding events to the parent element of my custom tag's rendered content, then using classes to target the event onto the element which my custom tag actually renders. I feel this is likely to cause strange bugs. For instance, if anyone on my team places two custom tags using the same targeting-classes under the same immediate parent element, it would cause multiple events to fire, associated with the wrong elements.
Here's a sample of the code I'm using now:
$.views.tags({
toggleProp: {
template: '<span class="toggle">{{include tmpl=#content/}}</span>',
onAfterLink: function () {
var prop = this.tagCtx.view.data;
$(this.parentElem).on('click', '.toggle', function () {
prop.value(!prop.value());
});
},
onDispose: function () {
$(this.parentElem).off('click', '.toggle');
}
}
// ... other custom tags simply follow the same pattern ...
});
By the time we hit onAfterLink, is there any reliable way to access the rendered DOM Element (or DOM Elements) corresponding to the custom tag itself? With no risk of hitting the wrong element by mistake? I understand that the custom tag may be text without an HTML Element, but it would still be a text node, right? (Could I even bind events to text nodes?)
In other places, and using (far) older versions of JsViews, I've bound events after the render using (sometimes a lot of) targeting logic built into the rendered elements as data- attributes. Not only is this a far more fragile method than I like for accessing the rendered data, it would be incredibly risky and convoluted to try to apply this approach to some of our deeply-nested-and-collection-ridden templates.
I also don't like needing to insert a span with my custom tag, just so I can apply classes to it, but if it's still necessary for the event, I'll cope.
I ask, then, what is a safe, modular way to bind events to the DOM so that I also have access to the data rendered directly against those elements?
Edit: As an additional concern, using onAfterLink won't let me bind events to non-data-linked rendered content. This may be part of the design intent of JsViews vs pure JsRender, but I don't yet understand why that would be the case.
Rather than using this.parentElem, you can use
this.contents()
which is a jQuery object containing all immediate content elements within the tag.
You can also provide a selector argument,
this.contents("someselector")
to "filter" , and include an optional boolean "deep" flag to both "filter" and "find" - i.e.
this.contents("someselector", true).
Using the above APIs ensures you are only taking elements that are actually within the tag content.
You may not need to remove the handlers in onDispose, if the tag is only deleted along with its content, you can rely on the fact that jQuery will dispose handlers when the elements are removed from the DOM.
You can only attach events to elements, not to text nodes. So if your content does not include elements, you would need to add your wrapper element, but not otherwise.
$.views.tags({
toggleProp: {
template: '{{include tmpl=#content/}}',
onAfterLink: function () {
var prop = this.tagCtx.view.data;
this.contents().on('click', function () {
prop.value(!prop.value());
});
},
onDispose: function () {
this.contents().off('click');
}
}
});
Also take a look at samples such as http://www.jsviews.com/#samples/tagcontrols/tabs which use the above approach.
I want to know the most effctive way to dynamically update, insert or remove elements from an html page.
The outcome of this is that, I can change an input element into a div element and vice versa based on a user action.
eg
<form><input type="text" value="Value to save"/></form>
and based on some event, i will change that to
<form><div>Value to Save</div></form>
Tx
I think you could do this task this way (pure JS, without using external frameworks):
//retrieve the <form>
var form = document.getElementsByTagName('form')[0];
//retrieve the <input> inside the form
var input = form.getElementsByTagName('input')[0];
//create a new <div> DOM element
var newElement = document.createElement('div');
//The containing div text is equal to the input value (your case)
newElement.innerHTML = input.value;
//simple empty the form by set innerHTML = ""
form.innerHTML = "";
//append the <div> inside the form
form.appendChild(newElement);
By the way, I sugges you, if you want to manipulate DOM and do stuff like these in an easier way, learn how to do it by using frameworks like jQuery or mootools ;)
This is a general description:
Creating: You can create elements with document.createElement and then use one the various insertion methods to the insert the element at a certain position (e.g. Node.appendChild). You need to get references to related nodes first.
Most browser also support the innerHTML attribute for elements. You can set that attribute to an HTML(or text) string and the content of the element will be updated accordingly.
Updating: It depends on which data you want to update. E.g. an input element has an attribute value. In order to change the value of a text input you need to get a reference to that element first, then you can do element.value = 'new value'. For content, you can use the already mentioned innerHTML attribute.
Have a look at an HTML element reference to see what attributes they have.
Deleting: You want Node.removeChild.
I suggest to also have a look at DOM traversal methods and be aware of browser differences.
Using:
element.removeChild
element.appendChild
By using these methods, you can retain references to the elements in case you want to swap them back over again. Any event handlers in place will remain attached to the elements, too.
This depends on your definition of most effective.
If you mean the simplest way, then you can use a library like jQuery and do it like this:
$('form').html('<dynamic markup>');
If you mean the most performant way you can do the following:
document.getElementByTagName('form').innerHTML = '<dynamic markup>';
I create a new window when i press a button. This window contains html input elements that i want to manipulate with jquery, but i can't catch the elements. Normally i would use the live function because the html is first added to the dom when the button is pressed, but its not working.
jQuery(document).ready(function () {
var opretKnap = jQuery("input[value='Open window']");
jQuery(opretKnap).live('click', function () {
var inputsDate = jQuery("input[vdfDataType]");
});
});
jQuery("input[vdfDataType]");
What's vdfDataType? That's not a standard HTML attribute. Are you meaning to use custom attributes? (It's a generally questionable strategy, especially when you want to select on them.)
Is the element you're trying to get in the current document? You say it's a ‘new window’, but if you actually mean a new window and not an in-page DOM pop-up, you won't be able to select it from the document that opened it.
jQuery(opretKnap).live
should be avoided:
the .live() method should always be called directly after a selector
That is, the argument in the jQuery() wrapper immediately before the live() call should be a selector string, such as "input[value='Open window']" directly. opretKnap is a jQuery wrapper already, so opretKnap.live() would be OK.
jQuery("input[value='Open window']")
Avoid using value as an attribute selector. Apart from it not really being very specific (what happens if a text field somewhere happens to have that string in it?), it's also unreliable for many cases in jQuery.
The value HTML attribute and the value DOM property are two different things for text inputs (and some others); the property gives the current field value, whereas the attribute gives the original value that was specified in the HTML before any user input. This attribute maps to the DOM defaultValue property, not value.
However, a bug in the Sizzle selector engine used by jQuery means it'll read the value property in preference. This would give the ‘wrong’ (but possibly desired) results... but not consistently, because in many cases the browser's own querySelectorAll call will be used for speed, short-cutting Sizzle's bug.
Whilst this might not affect you (eg. if you're selecting a button, whose value will never change), you should consider the [value=...] selector to be highly suspect, and avoid it whenever possible. Find another way to pick the particular input you want, such as a .class, #id, [name="something"] or [type=submit] if that's what it is.
In jquery I've appended a <li> element to an unordered list.
How do I focus on the newly created <li> ?
If I do the following:
$("ul").append('<li><input type="text" value="Hi!"></li>');
$("li:last").focus(); //doesn't work because new <li> isn't in dom yet
the focus doesn't work, as noted above.
I know jquery 1.4.2 has a live() event handler which allows you load event handlers to dynamically added elements, but I'm not sure what I'm doing wrong:
$(document).ready(function () {
$('li').live('load', function () {
alert("hi!");
$("li:last").focus();
});
});
You can only set the focus to elements which can hold the focus. By default a list item cannot. This is why your first example fails, not because it isn't in the DOM (it is in the DOM, that is what append does)
In general you should use elements designed to hold the focus (i.e. set the focus on the input not the list item). You can also (but this is less backwards compatible and less logical) use HTML5's tabindex (probably setting it to 0).
onload will not work because list items do not load external content.
You can try this, $(YourElement).trigger("focus").
This is an old post I know, but a simple way to solve this issue is to create a text input in your HTML and set its CSS to "display: none;". On the LI's click event, set the focus in this input and listen to its keypress events.
I've done it and it works like a charm.