ng-blur is not triggered when I lose focus - javascript

So i've been trying to be able to change the title of a playlist by double clicking on it.
I'm using ng-blur to know when i lose focus on the edit, but the doneEditing function is never called. (editTitle and done editing just set playlist.editing to true and false and console.log editing and done editing).
.html
<html>
<head>
<meta charset="UTF-8">
<title>Playlist</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
</head>
<body>
<article ng-app>
<div class="todo-wrapper" ng-controller="TodoCtrl">
<h2 ng-hide="playlist.editing" ng-dblclick="editTitle(playlist)">{{playlist.title}}</h2>
<input ng-show="playlist.editing" ng-model="playlist.title" ng-blur="doneEditing(playlist)" autofocus />
<ul>
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done"/>
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>
<form>
<input class="add-input" placeholder="I need to..." type="text" ng-model="formTodoText" />
<button class="add-btn" ng-click="addTodo()"><h2>Add</h2></button>
</form>
<button class="clear-btn" ng-click="clearCompleted()">Clear completed</button>
</div>
</article>
<script src="js/index.js"></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js'></script>
</body>
</html>
.js
function TodoCtrl($scope) {
$scope.todos = [
{text:'Movie1', done:false},
{text:'Movie2', done:false}
];
$scope.playlist = {title: "New Playlist", editing:false};
$scope.getTotalTodos = function () {
return $scope.todos.length;
};
$scope.addTodo = function () {
$scope.todos.push({text:$scope.formTodoText, done:false});
$scope.formTodoText = '';
};
$scope.clearCompleted = function () {
$scope.todos = _.filter($scope.todos, function(todo){
return !todo.done;
});
};
$scope.editTitle = function (playlist) {
playlist.editing = true;
};
$scope.doneEditing = function (playlist) {
playlist.editing = false;
};
}
I'm not sure what i'm doing wrong here, because the examples I've found on fiddle (http://jsfiddle.net/davekr/F7K63/43/) are working fine using those lines.
PS : I've tested to run the code on both Firefox and Chrome, the doneEditing function has never been called.
Edit : Uploaded the full .html and .js files

You need to add ng-model="playlist.title"to the input tag
<h2 ng-hide="playlist.editing" ng-click="editTitle(playlist)">{{playlist.title}}</h2>
<input ng-show="playlist.editing" ng-model="playlist.title" ng-blur="doneEditing(playlist)" autofocus />
And if you add console.log("foo"); to the doneEditing function you can see that it is working correctly
EDIT
Here is a plunker
https://plnkr.co/edit/LoW9nkhYO5BIaOzuaxOX?p=preview
Update AngularJS to newest version or at least 1.2 <

Related

Making 2+ Text areas reflect each other

I am making a note-taking app and I want 2 text areas to when you type in one the other changes to
what you are doing in one. I want so when I change the title of the page it will change in other places on the page. I'll provide my current code what my page looks like (I want the change to be with my Unititled and an area next to the dropdown arrow) and what I want it to do, I've tried change and input events and I can't seem to figure it out.[My Current Site][1]
What I Want - https://share.vidyard.com/watch/Wj6uTmEiB9LR8iiZy7sVf9
[1]: https://i.stack.imgur.com/3vzEB.png
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Study App</title>
<link rel="stylesheet" href="study.css" />
<link href="https://unpkg.com/boxicons#2.0.7/css/boxicons.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-
awesome/5.15.1/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" charset="utf-
8"></script>
</head>
<body>
<script src="study.js"></script>
<div class="dropdown">
<nav><label for="touch"><span>Settings</span></label>
<input type="checkbox" id="touch" />
<ul class="slide">
<li><a>
<div class="dark"><button onclick="myFunction()">
<input class="toggle" type="checkbox" /></button></div>
</a></li>
<li></li>
</ul>
</nav>
</div>
</div>
<div class="arrowdown">
<input type="checkbox" id="myCheckbox" onchange="rotateElem()" checked><i class="fas fa-angle-
right dropdown"></i></button>
<div class="pages">
Add Page
</div>
</div>
</div>
<script type="text/javascript">
var checkBox = document.getElementById("myCheckbox");
function rotateElem() {
if (checkBox.checked == false) {
document.querySelector('.fas.fa-angle-right.dropdown').style.transform = 'rotate(90deg)';
} else {
document.querySelector('.fas.fa-angle-right.dropdown').style.transform = 'rotate(0deg)';
}
}
</script>
<div class="tabs"></div>
<div class="sidebar">
<div class="sidebar-top">
<h1><span class="study">Study</span><span class="app">App</span></h1>
</div>
<div class="title">
<textarea id="shortInput" spellcheck="true" placeholder="Untitled" cols="30" rows="1">
</textarea>
</div>
<div class="textbox">
<textarea id="longInput" spellcheck="true" placeholder="Start typing..." cols="30" rows="10"></textarea>
</div>
<script type="text/javascript">
$('.pages').hide();
$(document).ready(function() {
$('input').click(function() {
$('.pages').slideToggle();
});
});
</script>
<script src="study.js"></script>
</body>
</html>
One possible approach would be to store the synchronised value in a variable, and add event listeners to each element for any changes. Then update the value of each element with the new value when the change occurs.
// Store the synchronised content
let value = ''
// Add change listeners to each element
const elements = document.querySelectorAll('.synced')
for (let i = 0; i < elements.length; i++) {
// Different browsers will work better with different events
// but there's no problem with listening for multiple
elements[i].addEventListener('change', handleChange)
elements[i].addEventListener('input', handleChange)
elements[i].addEventListener('keyup', handleChange)
}
// When a change occurs, set the value of all the synchronised elements
function handleChange(e) {
value = e.target.value
for (let i = 0; i < elements.length; i++) {
elements[i].value = value
}
}
<textarea class="synced"></textarea>
<textarea class="synced"></textarea>
<textarea class="synced"></textarea>
jQuery version:
// Store the synchronised content
let value = ''
// Get all the of the relevant elements
const elements = $('.synced')
// Different browsers will work better with different events
// but there's no problem with listening for multiple
elements.on('change input keyup', function() {
value = $(this).val()
elements.val(value)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea class="synced"></textarea>
<textarea class="synced"></textarea>
<textarea class="synced"></textarea>

Javascript - Redirect if the value in a input box is correct

I have a problem, I'm doing a little game and I made a level, where you just have to change the level number to go to the next level, but when the correct value is sent it's supposed to redirect to the next level but it doesn't work ...
function getVal() {
var nmb = document.getElementById('input').value;
var element = document.getElementById('input');
element.addEventListener('keyup', function(event) {
if(nmb == 3) {
document.location.href = "aw3za.html"; //If the value is correct it redirects to the level 3
}
else {
document.location.href = "2ksdkwa.html"; //If the value isn't correct it stays on the level 2
}
})
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>RodrigueSS 2 | Level 2</title>
<link rel="stylesheet" href="assets/style/level_template.css">
<link rel="stylesheet" href="assets/style/level2_style.css">
<script src="https://kit.fontawesome.com/57d547920e.js" crossorigin="anonymous"></script>
<script src="assets/script/level2.js"></script>
<script type="text/javascript" src="assets/script/jquery-3.4.1.js"></script>
</head>
<body>
<header>
<div class="prev-page-container">
<img class="prev-page-arrow" src="assets/img/prev-arrow.svg" alt="Back arrow">
</div>
</header>
<!--This is the interesting part--------->
<div class="level-number-wrapper"></div>
<div class="level-number-container">
<form method="GET" name="form1">
<input onclick="getVal()" id="input" name="numbox1" class="level-number" type="number">
</form>
</div>
</div>
<!--------------------------------------->
<footer>
<div class="media-container">
<ul>
<li><a class="media-link" href="https://www.instagram.com/r_dr_go/"><i class="fab fa-instagram"></i></a></li>
<li><a class="media-link"href="https://twitter.com/Rodrigu40035063"><i class="fab fa-twitter"></i></a></li>
<i class="fas fa-arrow-right"></i>
</ul>
</div>
</footer>
</body>
</html>
To the people that have this problem, Here is the JS, I put a window.onload, it means that it only launch when the page is completely loaded :
window.onload = function() {
document.getElementById('input').addEventListener('keyup', function(event) {
if(document.getElementById('input').value == 3) {
window.location.href = "aw3za.html"
}
})
}
document.location has been deprecated for almost as long as JavaScript has existed. Don't use it So use window.location
function getVal() {
var nmb = document.getElementById('input').value;
var element = document.getElementById('input');
element.addEventListener('keyup', function(event) {
if(nmb == 3) {
window.location = "aw3za.html"; //If the value is correct it redirects to the level 3
}
else {
window.location = "2ksdkwa.html"; //If the value isn't correct it stays on the level 2
}
})
}
I don't understand why you need trigger onClick function on input box. that function only execute when you click on that. So when you clicking that value is empty. then when you try to perform keyup the value will be empty. Actually you can use document.location.href.
Problem is your arrangement. Try this
var element = document.getElementById('input');
element.addEventListener('keyup', function(event) {
var nmb = document.getElementById('input').value;
if(nmb == 3){
console.log('in');
document.location.href = "new.html";
}
})
<div class="level-number-wrapper">
<div class="level-number-container">
<form method="GET" name="form1">
<input id="input" name="numbox1" class="level-number">
</form>
</div>
</div>
Several things here:
First you have an extra div closing in the interesting part of your code here:
<div class="level-number-wrapper"></div>
you should erase it.
Second, you don't need to use the function getVal() to add an event listener, you should add it directly.
Last, if you are staying in the same page if unless you change the value to 3 then you don't need the else part of the if.
This being said, this code works for me, check it out:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>RodrigueSS 2 | Level 2</title>
<link rel="stylesheet" href="assets/style/level_template.css">
<link rel="stylesheet" href="assets/style/level2_style.css">
<script src="https://kit.fontawesome.com/57d547920e.js" crossorigin="anonymous"></script>
<script src="assets/script/level2.js"></script>
<script type="text/javascript" src="assets/script/jquery-3.4.1.js"></script>
</head>
<body>
<header>
<div class="prev-page-container">
<img class="prev-page-arrow" src="assets/img/prev-arrow.svg" alt="Back arrow">
</div>
</header>
<!--This is the interesting part--------->
<div class="level-number-wrapper">
<div class="level-number-container">
<form method="GET" name="form1">
<input id="input" name="numbox1" class="level-number" type="number">
</form>
</div>
</div>
<!--------------------------------------->
<footer>
<div class="media-container">
<ul>
<li><a class="media-link" href="https://www.instagram.com/r_dr_go/"><i class="fab fa-instagram"></i></a></li>
<li><a class="media-link"href="https://twitter.com/Rodrigu40035063"><i class="fab fa-twitter"></i></a></li>
<i class="fas fa-arrow-right"></i>
</ul>
</div>
</footer>
<script>
document.getElementById('input').addEventListener('keyup', function(event) {
if(document.getElementById('input').value == 3) {
document.location.href = "aw3za.html"
}
})</script>
</body>
</html>
I think you can use both location and window but window is a bit better for cross browser safety as stated here:
What's the difference between window.location and document.location in JavaScript?
window.open
Calling window.open function in the listener had made the browser open the tab.
Here is the working code:
1. index.html
<!DOCTYPE html>
<html>
<body>
<div class="level-number-wrapper">
<div class="level-number-container">
<form method="GET" name="form1">
<input id="input" name="numbox1" class="level-number" type="number">
</form>
</div>
</div>
<script>
document.getElementById('input').addEventListener('keyup', function(event) {
if(document.getElementById('input').value == 3) {
window.open("aw3za.html")
}
})</script>
</body>
</html>
2. aw3za.html
<!DOCTYPE html>
<html>
<head>
<title> Level 2</title>
</head>
<body>
<h1>AW3ZA</h1>
</body>
</html>
Try to replace
document.location.href
By
window.location

Issue with angular auto populating the create form when I click on the edit form

I created a simple phonebook app with CRUD functionality in Angular. I am having an issue where Angular's ng-model is auto populating my create form when I click on my edit button that has its own form for editing. How can I separate the two forms without losing functionality? Picture of Issue If the code is not readable, I have linked my project on github: contacts_angular_practice
<-- index.html -->
<!DOCTYPE html>
<html lang="en" ng-app="contactsApp">
<head>
<meta charset="UTF-8">
<title>Contacts</title>
<link href='https://fonts.googleapis.com/css?family=Varela+Round' rel='stylesheet' type='text/css'>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
<script src="scripts/app.js"></script>
<script src="controllers/main.js"></script>
<link href="css/styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Contacts</h1>
<!-- create functionality-->
<div ng-controller="mainController as mainCtrl" class="list">
<div class="add">
+ Add a New Contact
<form ng-show="mainCtrl.formIsVisible" ng-submit="mainCtrl.create()">
<label>Name</label>
<input placeholder="Enter Name" class="createInput" type="text" name="name" ng-model="mainCtrl.name">
<label>Phone Number</label>
<input placeholder="Enter Phone Number" class="createInput" type="text" name="phoneNumber" ng-model="mainCtrl.phoneNumber">
<button class="new">New Contact</button>
</form>
</div>
<!-- edit, update and delete functionality -->
<div class="item" ng-repeat="contact in mainCtrl.contacts">
<!-- | orderBy:'-name': true -->
<!-- show data -->
<div ng-show=!editContact>
<label ng-show="!editContact">{{contact.name}}</label>
<label ng-show="!editContact">{{contact.phoneNumber}}
</label>
</div>
<!-- form for editing -->
<form ng-show="editContact">
<input ng-model="mainCtrl.name" class="editing-label" type="text"/>
<input ng-model="mainCtrl.phoneNumber" class="editing-label" type="text"/>
</form>
<!-- edit, save and delete buttons -->
<div class="actions">
Edit
Save
Delete
</div>
</div>
</div>
</body>
</html>
<-- app.js -->
'use strict';
(function() {
var app = angular.module('contactsApp', [
'mainController'
])
})()
<-- main.js(controller) -->
(function() {
angular.module("contactsApp", [])
.controller("mainController", function() {
this.contacts = [
{"id": "0", "name":"Carson Daly", "phoneNumber":"000-000-0000"},
{"id": "1", "name":"Britney Spears", "phoneNumber":"000-000-0000"},
{"id": "2", "name":"Freddie Prince Jr", "phoneNumber":"000-000-0000"},
{"id": "3", "name":"Halle Berry", "phoneNumber":"000-000-0000"},
{"id": "4", "name":"Gary Oldman", "phoneNumber":"000-000-0000"},
{"id": "5", "name":"Aaron Carter", "phoneNumber":"000-000-0000"}
]
this.formIsVisible = false
this.toggleForm = function() {
console.log("toggleform")
if(this.formIsVisible){
this.formIsVisible = false
}
else {
this.formIsVisible = true
}
}
this.reset = function(){
this.name = ""
this.phoneNumber = ""
}
this.create = function() {
console.log("clicked")
this.contacts.unshift({
name: this.name,
phoneNumber: this.phoneNumber
});
this.reset()
};
this.edit = function(index) {
var contact = this.contacts[index];
this.name = contact.name;
this.phoneNumber = contact.phoneNumber;
};
this.update = function(index) {
var contact = this.contacts[index];
contact.name = this.name;
contact.phoneNumber = this.phoneNumber;
};
this.delete = function(index){
console.log("whats up")
console.log(index)
this.contacts.splice(index, 1);
};
});
})();
I figured out the answer by installing ng-Inspector browser extension.
I immediately saw that I wrote two controllers on the line:
<div ng-controller="mainController as mainCtrl">
I thought I was creating a shortcut. I changed the the line to:
<div ng-controller="mainCtrl">
After that It worked great. I had to change my functions to reference $scope instead of this in the controller. I also had to change ng-models in the index.html file from mainCtrl.name to contact.name. After I made these changes it worked perfectly. The changes can be seen on my github link to the project: contacts_angular_practice

When I click the button, function doesn't get called [duplicate]

This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 8 years ago.
I'm new to JavaScript and JQuery, and I'm trying to figure out why my function doesn't get called when I press the button. My only clue is that the Firefox Console is showing TypeError: document.getElementById(...) is null. I found this example, which says "document.write will overwrite the entire DOM if it's called after the document has finished being parsed" and that's why it's happening. I took a look at my code, and I moved the button into my div tag and it's still happening. I also tried moving the button into it's own div tags. Compiler didn't seem to like syntax when I tried adding html tags where the button is. I'm not sure what I'm supposed to do to fix this.
I'm following this example for the function call on button click. Hopefully I'm applying it ok to my project.
This is my code:
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<title>jQuery Michele Project</title>
<link href="css/skins/polaris/polaris.css" rel="stylesheet">
<link href="css/skins/all.css" rel="stylesheet">
<link href="css/demo/css/custom.css" rel="stylesheet">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="js/jquery-1.11.0.js"></script>
<script type="text/javascript" src="js/jquery.ui.core.js"></script>
<script type="text/javascript" src="js/jquery.ui.widget.js"></script>
<script src="js/icheck.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.input').iCheck({
checkboxClass:'icheckbox_polaris',
radioClass:'iradio_polaris',
increaseArea:'10%'
});
});
</script>
<script type="text/javascript">
// Returns an array with values of the selected (checked) checkboxes in "frm"
function getSelectedChbox(frm) {
// JavaScript & jQuery Course - http://coursesweb.net/javascript/
var selchbox = []; // array that will store the value of selected checkboxes
// gets all the input tags in frm, and their number
var inpfields = frm.getElementsByTagName('input');
var nr_inpfields = inpfields.length;
// traverse the inpfields elements, and adds the value of selected (checked) checkbox in selchbox
for(var i=0; i<nr_inpfields; i++) {
if(inpfields[i].type == 'checkbox' && inpfields[i].checked == true)
selchbox.push(inpfields[i].value);
}
return selchbox;
}
document.getElementById('btntest').onclick = function() {
var selchb = getSelectedChbox(this.form);
alert(selchb);
}
</script>
<style type="text/css">
ul {list-style-type: none}
img {padding-right: 20px; float:left}
#infolist {width:500px}
</style>
</head>
<body>
<form>
<div class="skin skin-line">
<div class="arrows">
<div class="top" data-to="skin-flat"></div>
<div class="bottom" data-to="skin-polaris"></div>
</div>
</div>
<div class="skin skin-polaris">
<div class="arrows">
<div class="top" data-to="skin-line"></div>
<div class="bottom" data-to="skin-futurico"></div>
</div>
<h3>Select Items for Column Headings</h3>
<dl class="clear">
<dd class="selected">
<div class="skin-section">
<h4>Live</h4>
<ul class="list">
<li>
<input tabindex="21" type="checkbox" id="polaris-checkbox-1">
<label for="polaris-checkbox-1">Checkbox 1</label>
</li>
<li>
<input tabindex="22" type="checkbox" id="polaris-checkbox-2" checked>
<label for="polaris-checkbox-2">Checkbox 2</label>
</li>
<li>
<input type="checkbox" id="polaris-checkbox-3" >
<label for="polaris-checkbox-3">Checkbox 3</label>
</li>
<li>
<input type="checkbox" id="polaris-checkbox-4" checked >
<label for="polaris-checkbox-4">Checkbox 4</label>
</li>
</ul>
</div>
<script>
$(document).ready(function(){
$('.skin-polaris input').iCheck({
checkboxClass: 'icheckbox_polaris',
radioClass: 'iradio_polaris',
increaseArea: '20%'
});
});
</script>
//$('#checkbox').prop('checked')
</dd>
</dl>
</div>
<div id="loading">
<input type="button" value="Click" id="btntest" />
</div>
</form>
</body>
</html>
The issue is you assign the click handler before the element is available in the DOM. To resolve, you should wrap it in a DOM ready function:
$(function(){
document.getElementById('btntest').onclick = function() {
var selchb = getSelectedChbox(this.form);
alert(selchb);
}
});
Note: $(function(){ ... }); is a shortcut for $(document).ready(function(){ ... });
You're running document.getElementById('btntest') before that element exists. Put this script after your button on the page, not before it:
<script>
document.getElementById('btntest').onclick = function() {
var selchb = getSelectedChbox(this.form);
alert(selchb);
}
</script>

Angularjs templating: model and function stop working in external templates?

After this question, I am facing another challenge, the model and function inside the $scope seem have stopped working. Below is the test code, the Add button seem does not collect any data I input from <input type='text' ng-model='newPerson' /> anymore,
html,
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>AngularJS</title>
<meta charset="utf-8">
<script src="js/jquery-1.10.1.min.js"></script>
<script src="js/angular.min.js"></script>
<script src="js/app.js" type="text/javascript"></script>
</head>
<body>
<div ng-app='MyTutorialApp' ng-controller='MainController'>
<div ng-include='thisIsAScopeProperty'></div>
</div>
</body>
</html>
the external template,
<div id='content'>
<input type='text' ng-model='searchText' />
<ul>
<li ng-repeat='person in people | filter:searchText' ng-show='person.live == true'>#{{person.id}} {{person.name}}</li>
</ul>
<input type='text' ng-model='newPerson' />
<button ng-click='addNew()'>Add</button>
</div>
angularjs,
var app = angular.module('MyTutorialApp',[]);
app.controller("MainController", function($scope){
$scope.thisIsAScopeProperty = 'template/index.html';
$scope.people = [
{
id: 0,
name: 'Leon',
music: [
'Rock',
'Metal',
'Dubstep',
'Electro'
],
live: true
}
];
$scope.newPerson = null;
$scope.addNew = function() {
alert(1); // works here when you click the Add button
console.log($scope.newPerson); // but returns nothing when you type any text in the input
if ($scope.newPerson != null && $scope.newPerson != "") {
alert(2); // does not work here
$scope.people.push({
id: $scope.people.length,
name: $scope.newPerson,
live: true,
music: [
'Pop',
'RnB',
'Hip Hop'
]
});
}
}
});
Any ideas why and how can I fix it?
Use
<input type='text' ng-model='$parent.newPerson' />
ng-include creates a new scope, and because newPerson is a simple property, it's a different one on the child and parent scopes (i.e. changing one doesn't change the other). So when the included template sets newPerson it's still null on the mainController's scope.
For a better understanding of how scopes work, read https://github.com/angular/angular.js/wiki/Understanding-Scopes

Categories

Resources