There is a way to get the input that binding a model's property.
I want to do this to blur the search input after I send the form,
and I want to do this dynamically for later changes in html source.
Example:
var app = angular.module("MyApp", []);
app.controller('ctrl', function($scope) {
$scope.term = 'test';
$scope.submit = function(){
document.querySelector('#search').blur();
// I want replace document.querySelector('#search') with something like 'getElementByProp($scope.term)'
};
});
<!DOCTYPE html>
<html data-ng-app="MyApp">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div data-ng-controller="ctrl">
<form data-ng-submit="submit()">
<input id="search" type="search" data-ng-model="term" />
</form>
</div>
</body>
</html>
There's a fundamental error in your intention here.
Please keep the following always in mind:
The controller should know absolutely nothing about the DOM
This is a precious rule of thumb that will help you a lot.
Now, of course you need to interact with the DOM from your javascript (AngularJS code), and for that you should use Directives.
In your case though I would use another approach:
if (document.activeElement) {
document.activeElement.blur();
}
This will work for any focused elements and you won't need to specifically query any DOM element.
So in theory you're not giving the controller any knowledge about the DOM, so for me this doesn't break the rule I mentioned above.
Just as a side note, $document for some reaon doesn't expose this activeElement.
I don't have time to dig into the code to see why but as far as I've tested you need to stick with the native document object.
An easy way to do this is using the jQuery little version that comes with AngularJS.
Try this:
var element = angular.element('[ng-model="YOUR_MODEL_NAME_HERE"]');
element.blur(); // element is a jQuery object
This should work
The reason this is not possible is that this is not something you'll usually want to do in Angular - you're most likely still "thinking like you're using jQuery". Please elaborate on why you want to manipulate the DOM yourself in the first place. Most likely it's a different problem that you can solve with e.g. a directive.
(This may sound like a lame answer, but "don't do this" very likely is the only correct way to handle this situation.)
Related
I've been playing around with web development and wanted to create a basic application which allows users to enter html into a text area, which is saved in local storage, then later inserted into a document element with .innerHTML.
Minimum working example:
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Prototyping</title>
</head>
<body>
<!--- Using bootstrap v. 5.2.0 --->
<form>
<label for="content"></label>
<textarea class="form-control" id="content"></textarea>
</form>
<div id="displayContent"></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
crossorigin="anonymous"></script>
<script src="index.js"></script>
</body>
</html>
JavaScript
const userInput = document.getElementById('content');
const displayInput = document.getElementById('displayContent')
userInput.addEventListener('input', (event) => {
localStorage.setItem(event.target.id, event.target.value);
displayInput.innerHTML = localStorage.getItem(event.target.id);
});
Now I was concerned that using .innerHTML would allow users to inject js code <script>alert('HAHA')</script>. However, scripts fail to run. Or at least with my limited knowledge of HTML, I cannot get a script to run. This is what I want, but I don't understand why. When inspecting the page, I will see the <script>. Is this because localStorage converts the input into strings? What is happening that prevents the script from running?
The reason why the alert you try to inject "fails to run", is because at this stage the DOM is already parsed and all the javascript within it is already executed. So, the code would not be executed again.
Still, since you are inserting HTML, any HTML that will be added, will also be rendered. And with that, there are also some ways to execute javascript-code like this. One example is the following snippet as an input:
<img src=z onerror="alert('Injected code')">
Similar results could be achieved with other event-listener-attributes or deferred scripts.
However, if you only save and open the input on the client-side and not expose it to other users, there is no way it could do any damage. It would be the same as if you use the console in the developer-menu that is built-in in every modern browser (F12 in most of them).
If that is still a problem for your use-case or you expose the inputs to other users, I would strongly recommend you to parse the text-input so that no js-code would be executed.
Probably the safest way of achieving this could be to only insert text instead of HTML:
displayInput.textContent = localStorage.getItem(event.target.id)
Another way could be could be to encode the < and > to their html equivilant (source):
let content = event.target.value.replace(/</g, "<").replace(/>/g, ">")
localStorage.setItem(event.target.id, content)
displayInput.innerHTML = localStorage.getItem(event.target.id)
I hope this helps. Keep it up!
Im new to Javascript and this site. Below are 2 codes (only HTML, normal i work with external js files) which deliver a button what you can click for a date. I was wondering which code has the preference amongst the developers and is there any advantage from 1 another? The way i see it is that adding a function is overkill.
Code 1
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta charset="utf-8">
</head>
<body>
<button onclick="document.getElementById('demo').innerHTML = Date()">The time is?</button>
<p id="demo"></p>
</body>
</html>
Code 2
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta charset="utf-8">
</head>
<body>
<button onclick="myFunction()">The time is?</button>
<p id="demo"></p>
<script>
function myFunction() {
document.getElementById("demo").innerHTML = Date();
}
</script>
</body>
</html>
The second one is way better, you are separating the js from the html.
If you have two buttons with the same function, it will be easier to avoid duplicated code and to maintain with the second version!
For example if you want to change the behaviour of your buttons, you won't have to modify your html and be able to change the beviour every where at once.
In my opinion the correct answer here is neither of both.
To write maintainable and readable code, the best practice is to have a complete separation between HTML, CSS and JavaScript. Making the assumption that "it's only one line", is pretty dangerous, as one line quickly becomes two and so on. It's better to always use the same rules instead of making exceptions for one-liners.
Personally, I would write HTML like this:
<button class="time-button"></button>
<p id="demo"></p>
<script src="script.js"></script>
In script.js, you can then attach an event listener like this:
// Note that querySelector might not be supported in really old browsers
var timeButton = document.querySelector('.time-button');
var demoParagraph = document.getElementById('demo');
// Or attachEvent for IE < 11
timeButton.addEventListener('click', timeFunction);
/**
* Here you can write some beautiful comments about the function
*/
function timeFunction (eventData) {
demoParagraph.innerHTML = new Date().toISOString();
}
In case you write it like that you can start listening (addEventListener) and stop listening (removeEventListener) whenever you want to.
It's recommended to put the elements in a variable, since looking up an element is pretty slow.
I'd say :
Both are correct depending on what you want to do with it.
First way : OK if the function is short and not complex, no re-use purpose.
Second way : OK if the function is complex, need to be maintained and plus : you can re-use it and avoid code duplication.
Now another approach is to extract javascript methods in another .js file.
Okay, I should preface this by saying I'm pretty new to JS and HTML.
I am attempting to write a simple page that will take the value a user types into the form and use it to make a call to the Spotify api via my findArtist() function. I've set the project up with npm and have the proper dependencies in the node-modules directory and all of that stuff.
Here is my code:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>My Title</title>
</head>
<body>
<header>
<h1>My Header</h1>
</header>
<section>
<form>
Search for an artist! <br/>
<input type="text" name="searchrequest" value="" onchange="findArtist()">
</form>
</section>
<script>
function findArtist () {
var artistName = document.getElementsByName("searchrequest")[0].value;
spotifyApi.searchArtists(artistName)
.then(function(data) {
console.log(data.body);
}, function(err) {
console.error(err);
});
}
</script>
</body>
</html>
When I type something in the search bar, I expect to see the call occur in my browsers console, where the JSON should be logged thanks to findArtist(), but nothing happens. Is this because I am attempting to use node when I should be using plain JS? Do I have to setup a server to make the call? I'm rather confused as to what my actual problem is.
I would like to add that I realize using onchange to call my function is going to put me over my api limit, so a suggestion on a better way to call the function would be appreciated as well.
Thanks for the help.
onchange detects changes only after you lose focus or blur from the textbox.
As this answer says oninput might just be the right method to look upto.
Really getting in to javascript and looking around at some patterns. One I have come accross is the module pattern. Its seems like a nice way to think of chucks of functionality so I went ahead and tried to implement it with jQuery. I ran in to a snag though. Consider the following code
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>index</title>
<script type="text/javascript" charset="utf-8" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
var TestClass2 = (function(){
var someDiv;
return {
thisTest: function ()
{
someDiv = document.createElement("div");
$(someDiv).append("#index");
$(someDiv).html("hello");
$(someDiv).addClass("test_class");
}
}
})();
TestClass2.thisTest();
});
</script>
</head>
<body id="index" onload="">
<div id="name">
this is content
</div>
</body>
</html>
The above code alerts the html content of the div and then adds a class. These both use jQuery methods. The problem is that the .html() method works fine however i can not add the class. No errors result and the class does not get added. What is happening here? Why is the class not getting added to the div?
Ah, now that you've updated your question I can better answer your question. You should change the append to appendTo considering you're wanting to move the newly created element inside of the already present #index.
$(document).ready(function() {
var TestClass2 = (function() {
var someDiv = $("#name");
return {
thisTest: function() {
someDiv = document.createElement("div");
$(someDiv)
.html("hello")
.addClass("test_class")
.appendTo("#index");
}
}
})();
TestClass2.thisTest();
});
Hope this helps!
I copied and pasted your code and it works for me.
Make sure you're not simply viewing source to see if the class is applied because doing so simply shows you the HTML that was sent from the server - any DOM updates that occur through JavaScript will not be reflected.
To view the live DOM, use a tool like Firebug or WebKit's Inspector (comes built-in to Safari and Chrome).
Your code works great!
http://jsfiddle.net/lmcculley/p3fDX/
I'm totally new to dojo ... and am drawing from my experience with jQuery somewhat ...
I have several elements like so:
<input name="info1" value="" style="width:52px" contstraints="{pattern:'#'}" dojoType="dijit.form.NumberTextBox"/>
<input name="info2" value="" style="width:52px" contstraints="{pattern:'#'}" dojoType="dijit.form.NumberTextBox"/>
<input name="info3" value="" style="width:52px" contstraints="{pattern:'#'}" dojoType="dijit.form.NumberTextBox"/>
But I'm having the hardest time tring to assign a simple onKeyUp event ... everything ive tried looks like it would work but doesn't ... console always reports that the thing im trying to do is not a function ...
dojo.addOnLoad(function()
{
dojo.query('input[name^=info]').connect('onkeyup',function(e)
{
console.log('oh yeah');
});
});
What am i doing wrong, what should I be looking out for ???
Unfortunately, dojo.query() will only return native DOM nodes. I think you want to get back the rendered Dijit Widget.
To do that, you'll need to assign your inputs IDs and use dijit.byId().
Also, unlike native HTML event names, Dojo event names are case-sensitive. So, onkeyup refers to the native HTML and is different from the Dojo event name onKeyUp.
I think you may also have an extra 't' in contstraints.
An example usage:
<html>
<head>
<title>Test</title>
<link type="text/css" rel="stylesheet" href="dijit/themes/tundra/tundra.css"/>
</head>
<body class="tundra">
<input id="input1" name="input" type="text"dojoType="dijit.form.NumberTextBox"/>
<script type="text/javascript" src="dojo/dojo.js"
djConfig="isDebug: true, parseOnLoad: true"></script>
<script type="text/javascript">
dojo.require("dijit.form.NumberTextBox");
dojo.addOnLoad(
function() {
dojo.connect(dijit.byId("input1"), 'onKeyUp',
function(e) { console.log('oh yeah'); });
}
);
</script>
</body>
</html>
Dojo makes it easy to declare events without the pain of going through queries. Just put the event right in your markup. See http://docs.dojocampus.org/quickstart/events#events-with-dijit
<input name="info1" value="" style="width:52px" constraints="{places:0}" dojoType="dijit.form.NumberTextBox" onkeyup="console.log('key up')" />
It's more concise, and you don't need to name and look up references just to bind the event.
Either way, abboq is right, you'll usually want to deal with the widget directly rather than the DOM node, since instantiating a Dijit often ends up restructuring the DOM so that it looks very different from the original page. The widget acts as an abstraction.