I am trying to do a web app similar to google calendar. I have done the object and methods within it but now it's time to be able to add what I want as a task. My idea is for the user to add something to the input and that input being console.logged for now.
Any idea?
HTML
<div class="new-task" id="task-input">
<div id="add-new-task">Task: <input type="text"></div>
<div id="add-time">Time: <input type="text"></div>
<button class ="save-task" onclick="">Save task</button>
</div>
Javascript
var idCounter = 0
var tasksManager = {
array: [],
add: function(task){
taskObject = {
title: task,
idVerification: idCounter ++
}
tasksManager.array.push(taskObject)
},
show:function(id){
var i;
for (i = 0; i < tasksManager.array.length; i++) {
if(id === tasksManager.array[i].idVerification){
return tasksManager.array[i]
}
}
},
delete:function(task){
if(this.show){
tasksManager.array.splice(task)
}
}
}
var newTask = document.getElementById("add-new-task")
newTask.addEventListener('click',tasksManager.add())
console.log(tasksManager.array)
As you can see with console.log above the array index [0] is logged as undefined but I wanted the user to write in the input " Go to the gym" and this to be logged within the array.
Thanks
Some issues:
You are not assigning the click handler. Instead you execute it immediately (not on click).
When you call .add() you don't provide an argument: the name of the task
The click handler should be on the button element, not on the div that has the input element. And so it will be useful to give that button an id attribute.
You should retrieve the value from the input element, and so it would be more appropriate to give that element an id and not so much the div that wraps it.
The console.log at the end of your script is executed immediately. It should be done only when the user has clicked the button.
Snippet with some corrections (also in the HTML!):
var idCounter = 0
var tasksManager = {
array: [],
add: function(task){
let taskObject = {
title: task,
idVerification: idCounter ++
}
tasksManager.array.push(taskObject)
},
show:function(id){
var i;
for (i = 0; i < tasksManager.array.length; i++) {
if(id === tasksManager.array[i].idVerification){
return tasksManager.array[i]
}
}
},
delete:function(task){
if(this.show){
tasksManager.array.splice(task)
}
}
}
var button = document.getElementById("save-task"); // <-- the button
var input = document.getElementById("add-new-task"); // <-- the input (move the ID attribute to the input!)
button.addEventListener('click', () => {
tasksManager.add(input.value);
console.log(tasksManager.array)
})
<div class="new-task" id="task-input">
<div >Task: <input id="add-new-task" type="text"></div>
<div id="add-time">Time: <input type="text"></div>
<button class ="save-task" id ="save-task" onclick="">Save task</button>
</div>
Related
I want to add html elements to the body of my page as an unordered list. I have used DocumentFragment method to create a fragment of the reply button and comment span. Now I need to add a textbox and a add reply to that ul whenever a user clicks on the reply button and add all the replies as a list next to respective comment. Here is what I've tried:
function comment() {
var my_comment = document.getElementById('comments');
my_comment.innerHTML = "<textarea id='user_comment'> </textarea> <button onclick='addNewItem()'>Post Comment</button>";
}
function addNewItem() {
var thediv = document.getElementById("comments_and_replies");
var listItem = document.createElement("ul");
var replyBox = document.createElement("textbox");
var commentSpan = document.createElement("span");
var user_comment = document.getElementById('user_comment');
var replyButton = document.createElement("button");
listItem.className = "comments-list";
replyButton.innerText = "Reply";
replyButton.className = "reply";
replyButton.addEventListener("click", function() {
var g = document.getElementById('comments_and_replies');
for (var i = 0, len = g.children.length; i < len; i++) {
(function(index) {
g.children[i].onclick = function() {
listItem.insertBefore(replyBox, listItem.children[index]);
}
})(i);
}
})
commentSpan.textContent = user_comment.value;
var documentFragment = document.createDocumentFragment();
documentFragment.appendChild(listItem);
listItem.appendChild(commentSpan);
listItem.appendChild(replyButton);
thediv.appendChild(documentFragment);
}
<section><button onclick="comment()">Leave a comment</button></section>
<div id="comments"></div>
<div id="comments_and_replies"></div>
Event delegation on a single <form> can accommodate an unlimited amount of <button>s even if they are added after the page has loaded.
The example below uses the following:
document.forms
.elements
event.currentTarget
event.target
.matches()
.insertAdjacentHTML()
.previousElementSibling
.parentElement
.remove()
Note: Unless you are submitting data to a server, add type="button" to each <button>
Details are commented in code below
// Refernce <form>
const form = document.forms.commentsReplies;
// Any click on <form> invokes post()
form.onclick = post;
// Pass the event
function post(event) {
/* Reference all <fieldset>
(also <button>, <textarea>, etc) */
const field = event.currentTarget.elements;
// Reference the actual element clicked
const clicked = event.target;
// if element clicked has class postCom
if (clicked.matches('.postCom')) {
/* find <fieldset name="post"> and
insert HTML into it */
field.post.insertAdjacentHTML('beforeEnd', `<fieldset name='commentPost'><textarea></textarea><button class='comTxt' type='button'>Done</button></fieldset>`);
// Otherwise if clicked element has class comTxt
} else if (clicked.matches('.comTxt')) {
/* find the clicked element's element
that is right before it and get it's text */
const text = clicked.previousElementSibling.value;
/* find <fieldset name='comments'> and insert HTML */
field.comments.insertAdjacentHTML('afterBegin', `<fieldset>${text}<button class='postRep' type='button'>Reply</button><ul></ul></fieldset>`);
// Remove <fieldset name='commentPost'>
field.commentPost.remove();
} else if (clicked.matches('.postRep')) {
clicked.insertAdjacentHTML('afterEnd', `<ul><textarea></textarea><button class='repTxt' type='button'>Done</button></ul>`);
} else if (clicked.matches('.repTxt')) {
const text = clicked.previousElementSibling.value;
const list = clicked.parentElement;
list.insertAdjacentHTML('afterBegin', `<li>${text}<button class='postRep' type='button'>Reply</button></li>`);
clicked.previousElementSibling.remove();
clicked.remove();
} else {
return false;
}
}
button {
display: block;
margin-left: 25%;
}
<form id='commentsReplies'>
<fieldset name='post'><button class='postCom' type='button'>Leave a comment</button>
</fieldset>
<fieldset name="comments">
<legend>Comments</legend>
</fieldset>
</form>
Can someone tell me what the best way to achieve the same thing seen here with this js:
function ContactController($scope) {
$scope.contacts = ["hi#me.no", "hi#you.com"];
$scope.addMail = function() {
if(this.mailAdress) {
$scope.contacts.push($scope.mailAdress);
$scope.mailAdress = "";
}
};
}
without the use of Angular. I am just trying to learn how save user input to the DOM using javascript. Thanks!
One way of doing the same is
var contacts = ["hi#me.no", "hi#you.com"],
ul = document.querySelectorAll('.email-list')[0];
// Iterate over the contacts and append it to the ul
for (var i = 0; i < contacts.length; i++) {
addEmailToContacts(contacts[i]);
}
function addEmailToContacts(contact) {
var li = document.createElement('li');
li.innerHTML = contact;
ul.appendChild(li);
};
// Click event for the submit
document.querySelector('#submit').addEventListener('click', function(e) {
e.preventDefault();
// Get the value
var value = document.querySelectorAll('input[type="mail"]')[0].value;
if (value) {
addEmailToContacts(value);
}
})
Check Codepen
You can use form element, input type="email" element with required attribute, onsubmit event, event.preventDefault(), Array.prototype.push() , Array.prototype.forEach(), .innerHTML
var contacts = ["hi#me.no", "hi#you.com"],
div = document.getElementById("update");
function updateContacts() {
div.innerHTML = "";
contacts.forEach(function(address) {
div.innerHTML += address + "<br>"
})
}
updateContacts();
document.forms[0].onsubmit = function(event) {
event.preventDefault();
// user input to update `contacts` array
contacts.push(this["input"].value);
// display updated `contacts` array
updateContacts();
}
<div id="update">
</div>
<form>
<input name="input" type="email" required />
<input type="submit" />
</form>
I'm creating a Time table generating website as a part of my project and I am stuck at one point.
Using for loop, I am generating user selected text boxes for subjects and faculties. Now the problem is that I cannot get the values of those dynamically generated text boxes. I want to get the values and store it into array so that I can then later on store it to database
If I am using localstorage, then it sometimes shows NaN or undefined. Please help me out.
Following is my Jquery code
$.fn.CreateDynamicTextBoxes = function()
{
$('#DynamicTextBoxContainer, #DynamicTextBoxContainer2').css('display','block');
InputtedValue = $('#SemesterSubjectsSelection').val();
SubjectsNames = [];
for (i = 0; i < InputtedValue; i++)
{
TextBoxContainer1 = $('#DynamicTextBoxContainer');
TextBoxContainer2 = $('#DynamicTextBoxContainer2');
$('<input type="text" class="InputBoxes" id="SubjectTextBoxes'+i+'" placeholder="Subject '+i+' Name" style="margin:5px;" value=""><br>').appendTo(TextBoxContainer1);
$('<input type="text" class="InputBoxes" id="FacultyTextBoxes'+i+'" placeholder="Subject '+i+' Faculty Name" style="margin:5px;" value=""><br>').appendTo(TextBoxContainer2);
SubjectsNames['SubjectTextBoxes'+i];
}
$('#DynamicTextBoxContainer, #UnusedContainer, #DynamicTextBoxContainer2').css('border-top','1px solid #DDD');
}
$.fn.CreateTimeTable = function()
{
for (x = 0; x < i; x++)
{
localStorage.setItem("Main"+x, +SubjectsNames[i]);
}
}
I am also posting screenshot for better understanding
I understand you create 2 text boxes for each subject, one for subject, and second one for faculty. And you want it as a jQuery plugin.
First of all, I think you should create single plugin instead of two, and expose what you need from the plugin.
You should avoid global variables, right now you have InputtedValue, i, SubjectsNames, etc. declared as a global variables, and I believe you should not do that, but keep these variables inside you plugin and expose only what you really need.
You declare your SubjectNames, but later in first for loop you try to access its properties, and actually do nothing with this. In second for loop you try to access it as an array, but it's empty, as you did not assign any values in it.
Take a look at the snippet I created. I do not play much with jQuery, and especially with custom plugins, so the code is not perfect and can be optimized, but I believe it shows the idea. I pass some selectors as in configuration object to make it more reusable. I added 2 buttons to make it more "playable", but you can change it as you prefer. Prepare button creates your dynamic text boxes, and button Generate takes their values and "print" them in result div. generate method is exposed from the plugin to take the values outside the plugin, so you can do it whatever you want with them (e.g. store them in local storage).
$(function() {
$.fn.timeTables = function(config) {
// prepare variables with jQuery objects, based on selectors provided in config object
var numberOfSubjectsTextBox = $(config.numberOfSubjects);
var subjectsDiv = $(config.subjects);
var facultiesDiv = $(config.faculties);
var prepareButton = $(config.prepareButton);
var numberOfSubjects = 0;
prepareButton.click(function() {
// read number of subjects from the textbox - some validation should be added here
numberOfSubjects = +numberOfSubjectsTextBox.val();
// clear subjects and faculties div from any text boxes there
subjectsDiv.empty();
facultiesDiv.empty();
// create new text boxes for each subject and append them to proper div
// TODO: these inputs could be stored in arrays and used later
for (var i = 0; i < numberOfSubjects; i++) {
$('<input type="text" placeholder="Subject ' + i + '" />').appendTo(subjectsDiv);
$('<input type="text" placeholder="Faculty ' + i + '" />').appendTo(facultiesDiv);
}
});
function generate() {
// prepare result array
var result = [];
// get all text boxes from subjects and faculties divs
var subjectTextBoxes = subjectsDiv.find('input');
var facultiesTextBoxes = facultiesDiv.find('input');
// read subject and faculty for each subject - numberOfSubjects variable stores proper value
for (var i = 0; i < numberOfSubjects; i++) {
result.push({
subject: $(subjectTextBoxes[i]).val(),
faculty: $(facultiesTextBoxes[i]).val()
});
}
return result;
}
// expose generate function outside the plugin
return {
generate: generate
};
};
var tt = $('#container').timeTables({
numberOfSubjects: '#numberOfSubjects',
subjects: '#subjects',
faculties: '#faculties',
prepareButton: '#prepare'
});
$('#generate').click(function() {
// generate result and 'print' it to result div
var times = tt.generate();
var result = $('#result');
result.empty();
for (var i = 0; i < times.length; i++) {
$('<div>' + times[i].subject + ': ' + times[i].faculty + '</div>').appendTo(result);
}
});
});
#content div {
float: left;
}
#content div input {
display: block;
}
#footer {
clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
<div id="header">
<input type="text" id="numberOfSubjects" placeholder="Number of subjects" />
<button id="prepare">
Prepare
</button>
</div>
<div id="content">
<div id="subjects">
</div>
<div id="faculties">
</div>
</div>
</div>
<div id="footer">
<button id="generate">Generate</button>
<div id="result">
</div>
</div>
I am making a To-do list, where I want to be able to add new tasks, and delete tasks that are checked off. However, it seems my function just deletes all tasks, not just the ones that are checked off. Neither does it seem to allow new tasks to be added.
html:
<h1 id="title"> To-do list</h1>
<div id="task_area">
</div>
<input type="text" id="putin"></input>
<button id="add">add</button>
javascript:
<button id="clear">Clear completed tasks</button>
var tasks = document.getElementById("task_area")
var new_task = document.getElementById("add")
var clear = document.getElementById("clear")
new_task.addEventListener("click", function() {
var putin = document.getElementById("putin")
var input = document.createElement('input')
input.type = "checkbox"
var label = document.createElement('label')
label.appendChild(document.createTextNode(putin.value))
task_area.appendChild(input)
task_area.appendChild(label)
})
clear.addEventListener("click", function() {
for (i = 0; i < task_area.children.length; i++) {
if (task_area.children[i].checked === true) {
task_area.remove(tasks.children[i])
}
}
})
jsfiddle: https://jsfiddle.net/4coxL3um/
.remove removes the element you are calling it from, and doesn't take an argument for what to remove. The following:
task_area.remove(tasks.children[i])
should be
tasks.children[i].remove()
EDIT: As Mononess commented below, this will only remove the checkboxes and not the labels. While you could delete both using Jayesh Goyani's answer below, it's probably better that each input/label pair be wrapped in a single div or span for easier management.
You could try adding an event listener to each child of task_area that calls the below function. Haven't gotten a chance to test it out, and may not fulfill all of your requirements, but should get the job done.
function removeClicked() {
this.parentNode.removeChild(this);
}
Please try with the below code snippet. Below code will help you to remove selected checkbox with label.
<body>
<h1 id="title">To-do list</h1>
<div id="task_area">
</div>
<input type="text" id="putin" />
<button id="add">add</button>
<button id="clear">Clear completed tasks</button>
<script>
var tasks = document.getElementById("task_area")
var new_task = document.getElementById("add")
var clear = document.getElementById("clear")
new_task.addEventListener("click", function () {
var putin = document.getElementById("putin")
var input = document.createElement('input')
input.type = "checkbox"
var label = document.createElement('label')
label.appendChild(document.createTextNode(putin.value))
task_area.appendChild(input)
task_area.appendChild(label)
//document.getElementById("task_area").innerHTML = putin.value
})
clear.addEventListener("click", function () {
for (i = 0; i < task_area.children.length; i++) {
if (task_area.children[i].checked === true) {
tasks.children[i].nextSibling.remove();
tasks.children[i].remove();
}
}
})
</script>
</body>
Please let me know if any concern.
I have two lists formed from an array containing objects.
I'm trying to move objects from one list to the other and vice versa.
Controller:
spApp.controller('userCtrl',
function userCtrl($scope,userService,groupService){
//Generate list of all users on the SiteCollection
$scope.users = userService.getUsers();
//array of objects selected through the dom
$scope.selectedAvailableGroups;
$scope.selectedAssignedGroups;
//array of objects the user actually belongs to
$scope.availableGroups;
$scope.assignedGroups;
//Generate all groups on the site
$scope.groups = groupService.getGroups();
//Boolean used to disable add/remove buttons
$scope.selectedUser = false;
//Take the selectedAvailableGroups, add user to those groups
//so push objects to "assignedGroups" array and remove from "avaiableGroups" array
$scope.addUserToGroup = function (){
userService.addUserToGroup($scope.selectedUser, $scope.selectedAvailableGroups, $scope.assignedGroups, $scope.availableGroups)
};
}
);
Service:
spApp.factory('userService', function(){
var addUserToGroup = function (selectedUser, selectedAvailableGroups, assignedGroups, availableGroups) {
var addPromise = [];
var selectLength = selectedAvailableGroups.length;
//Add user to selected groups on server
for (var i = 0; i < selectLength; i++) {
addPromise[i] = $().SPServices({
operation: "AddUserToGroup",
groupName: selectedAvailableGroups[i].name,
userLoginName: selectedUser.domain
});
};
//when all users added, update dom
$.when.apply($,addPromise).done(function (){
for (var i = 0; i < selectLength; i++) {
assignedGroups.push(selectedAvailableGroups[i]);
availableGroups.pop(selectedAvailableGroups[i]);
};
//alert(selectedUser.name + " added to: " + JSON.stringify(selectedAvailableGroups));
});
}
}
Object:
[{
id: 85,
name: Dev,
Description:,
owner: 70,
OwnerIsUser: True
}]
HTML:
<div>
<label for="entityAvailable">Available Groups</label>
<select id="entityAvailable" multiple
ng-model="selectedAvailableGroups"
ng-options="g.name for g in availableGroups | orderBy:'name'">
</select>
</div>
<div id="moveButtons" >
<button type="button" ng-disabled="!selectedUser" ng-click="addUserToGroup()">Add User</button>
<button type="button" ng-disabled="!selectedUser" ng-click="removeUserFromGroup()">Remove</button>
</div>
<div>
<label for="entityAssigned">Assigned Groups</label>
<select id="entityAssigned" multiple
ng-model="selectedAssignedGroups"
ng-options="g.name for g in assignedGroups | orderBy:'name'">
</select>
</div>
Right now, the push into assigned groups works but only updates when I click on something else or in the list, not really dynamically. But the biggest issue is the .pop() which I don't think works as intended.
$.when.apply($,addPromise).done() seems not to be angular api or synchronous. So angular is not aware of your changes. You must wrap your code inside a $scope.$apply call:
$scope.$apply(function(){
for (var i = 0; i < selectLength; i++) {
assignedGroups.push(selectedAvailableGroups[i]);
availableGroups.pop(selectedAvailableGroups[i]);
};
});
If you click on something, a $digest loop will happen and you will see your changes.
Your pop did not work because Array.pop only removes the last element. I guess that is not what you want. If you want to remove a specific element you should use Array.splice(),