I wrote a program with a pattern that takes names and numbers from inputs and stores them in an array.
And I wrote a function that takes these contacts from the array and creates tags for each contact and puts the name and number of the contact inside these tags.
The problem is that in the addbook function I called the showrecords function, then every time the existing contact list is added, the contacts are updated and the contacts are shown, but when I use the showrecords function, it gives an error inside the addbook function, which is not available.
Please help me solve my problem
function ElementBuilder(name) {
this.element = document.createElement(name);
this.appendSelector = function(selector) {
this.appendElement = document.querySelector(selector).appendChild(this.element);
return this
};
this.setAttribute = function(attribute, valueAttribute) {
this.element.setAttribute(attribute, valueAttribute)
return this;
};
this.addEventListener = function(event, fun) {
this.element.addEventListener(event, fun);
return this;
};
this.text = function(text) {
this.element.textContent = text;
return this;
};
this.build = function() {
return this.element;
};
}
const builder = {
create: function(name) {
return new ElementBuilder(name);
}
};
function PhoneBookRecord(name, phone) {
this.name = name;
this.phone = phone;
}
function PhoneBook() {
this.records = [];
const selectID = (idName) => document.getElementById(idName);
// function add contact
this.addbook = function() {
const self = this
function add() {
const letters = /^[A-Za-z]+$/;
const numbers = /^([0-9])+$/;
if ((selectID("name").value.match(letters)) && (selectID("phone").value.match(numbers))) {
const newContact = new PhoneBookRecord(selectID("name").value, selectID("phone").value);
self.records.push(newContact);
// The problem is that it cannot find this function until the contact list is displayed
showrecords();
}
return add;
}
}
}
function Render(container) {
this.container = container;
const phoneBook = new PhoneBook()
const add = phoneBook
.addbook();
const arry = phoneBook
.records;
// Function of elements Html
this.init = function() {
const btn = builder
.create("button")
.text("Add")
.addEventListener("click", add)
.setAttribute("id", "add")
.appendSelector("div")
.build();
const phoneBookContact = builder
.create("div")
.setAttribute("id", "addBook")
.appendSelector("div")
.build();
phoneBook.showrecords();
};
// Function: Read contacts from the array and display them
this.showrecords = function() {
const addBookId = document.getElementById('addBook');
const index = 0;
addBookId.innerHTML = '';
arry.forEach(elm => {
// Function of elements Html
const nameContent = builder
.create('li')
.text(`${elm.name}`)
.appendSelector("div>div")
.build();
const phoneContent = builder
.create('li')
.text(`${elm.phone}`)
.appendSelector("div>div")
.build();
});
}
}
const phoneBookContainer = document.getElementById("phone-book-container");
const app = new Render(phoneBookContainer);
app.init();
<form>
<label>Phone Book</label>
<input type="text" placeholder="name" id="name">
<input type="number" placeholder="phone" id="phone">
</form>
<div id="phone-book-container"></div>
These are the 2 steps i did to change the code and get to a working state.
Extract showrecords out of Render
pass the records to showrecords
I think this code needs a lot of work.
Here is a working JSFiddle: https://jsfiddle.net/jq5L7cdf/17/
Here is a snippet
function showrecords(arry) {
const addBookId = document.getElementById('addBook');
const index = 0;
addBookId.innerHTML = '';
arry.forEach(elm => {
// Function of elements Html
const nameContent = builder
.create('li')
.text(`${elm.name}`)
.appendSelector("div>div")
.build();
const phoneContent = builder
.create('li')
.text(`${elm.phone}`)
.appendSelector("div>div")
.build();
});
}
function ElementBuilder(name) {
this.element = document.createElement(name);
this.appendSelector = function(selector) {
this.appendElement = document.querySelector(selector).appendChild(this.element);
return this
};
this.setAttribute = function(attribute, valueAttribute) {
this.element.setAttribute(attribute, valueAttribute)
return this;
};
this.addEventListener = function(event, fun) {
this.element.addEventListener(event, fun);
return this;
};
this.text = function(text) {
this.element.textContent = text;
return this;
};
this.build = function() {
return this.element;
};
}
const builder = {
create: function(name) {
return new ElementBuilder(name);
}
};
function PhoneBookRecord(name, phone) {
this.name = name;
this.phone = phone;
}
function PhoneBook() {
this.records = [];
const selectID = (idName) => document.getElementById(idName);
// function add contact
this.addbook = function() {
const self = this
function add() {
const letters = /^[A-Za-z]+$/;
const numbers = /^([0-9])+$/;
if ((selectID("name").value.match(letters)) && (selectID("phone").value.match(numbers))) {
const newContact = new PhoneBookRecord(selectID("name").value, selectID("phone").value);
self.records.push(newContact);
// The problem is that it cannot find this function until the contact list is displayed
showrecords(self.records);
}
}
return add;
}
}
function Render(container) {
this.container = container;
const phoneBook = new PhoneBook()
const add = phoneBook
.addbook();
// Function of elements Html
this.init = function() {
const btn = builder
.create("button")
.text("Add")
.addEventListener("click", add)
.setAttribute("id", "add")
.appendSelector("div")
.build();
const phoneBookContact = builder
.create("div")
.setAttribute("id", "addBook")
.appendSelector("div")
.build();
showrecords(phoneBook.records);
};
// Function: Read contacts from the array and display them
this.showrecords = showrecords
}
const phoneBookContainer = document.getElementById("phone-book-container");
const app = new Render(phoneBookContainer);
app.init();
<form>
<label>Phone Book</label>
<input type="text" placeholder="name" id="name">
<input type="number" placeholder="phone" id="phone">
</form>
<div id="phone-book-container"></div>
EDIT:
use showrecords from Render
function ElementBuilder(name) {
this.element = document.createElement(name);
this.appendSelector = function(selector) {
this.appendElement = document.querySelector(selector).appendChild(this.element);
return this
};
this.setAttribute = function(attribute, valueAttribute) {
this.element.setAttribute(attribute, valueAttribute)
return this;
};
this.addEventListener = function(event, fun) {
this.element.addEventListener(event, fun);
return this;
};
this.text = function(text) {
this.element.textContent = text;
return this;
};
this.build = function() {
return this.element;
};
}
const builder = {
create: function(name) {
return new ElementBuilder(name);
}
};
function PhoneBookRecord(name, phone) {
this.name = name;
this.phone = phone;
}
function PhoneBook() {
this.records = [];
const selectID = (idName) => document.getElementById(idName);
// function add contact
this.addbook = function() {
const self = this
function add() {
const letters = /^[A-Za-z]+$/;
const numbers = /^([0-9])+$/;
if ((selectID("name").value.match(letters)) && (selectID("phone").value.match(numbers))) {
const newContact = new PhoneBookRecord(selectID("name").value, selectID("phone").value);
self.records.push(newContact);
// The problem is that it cannot find this function until the contact list is displayed
}
}
return add;
}
}
function Render(container) {
this.container = container;
const phoneBook = new PhoneBook()
const add = phoneBook
.addbook();
this.addEntry = () => {
add();
this.showrecords();
}
// Function of elements Html
this.init = function() {
const btn = builder
.create("button")
.text("Add")
.addEventListener("click", this.addEntry)
.setAttribute("id", "add")
.appendSelector("div")
.build();
const phoneBookContact = builder
.create("div")
.setAttribute("id", "addBook")
.appendSelector("div")
this.showrecords();
};
// Function: Read contacts from the array and display them
this.showrecords = () => {
const addBookId = document.getElementById('addBook');
const index = 0;
addBookId.innerHTML = '';
const arry = phoneBook.records;
arry.forEach(elm => {
// Function of elements Html
const nameContent = builder
.create('li')
.text(`${elm.name}`)
.appendSelector("div>div")
.build();
const phoneContent = builder
.create('li')
.text(`${elm.phone}`)
.appendSelector("div>div")
.build();
});
}
}
const phoneBookContainer = document.getElementById("phone-book-container");
const app = new Render(phoneBookContainer);
app.init();
<form>
<label>Phone Book</label>
<input type="text" placeholder="name" id="name">
<input type="number" placeholder="phone" id="phone">
</form>
<div id="phone-book-container"></div>
Related
I'm create simple pos web application using bootstrap for my semester project but at the last steps there is few errors that I cannot correct
I can't update this Item QTY using set ItemQTY function in ItemDTO
This is My ItemDTO
function itemDTO(id,name,QTY,price) {
const __id = id;
const __name = name;
const __QTY = QTY;
const __price = price;
this.getItemID = function () {
return id;
}
this.setItemID = function (itemID) {
id=itemID;
}
this.getItemName = function () {
return name;
}
this.setItemName = function (itemName) {
name=itemName;
}
this.getItemQTY = function () {
return QTY;
}
this.setItemQTY = function (itemQTY) {
QTY = itemQTY;
}
this.getItemPrice = function () {
return price;
}
this.setItemPrice = function (itemPrice) {
price = itemPrice;
}
}
This is my QTYupdate function
function changeQTY() {
let oldQty = parseInt($("#QTAvailable").val());
let QTY = parseInt($("#QTYorder").val());
let itemQTY = oldQty-QTY;
for (var i in ItemDB){
if ($("#itemNameNameDrop").val()==ItemDB[i].name){
$("#QTAvailable").val(itemQTY);
ItemDB[i].setItemQTY(itemQTY);
}
}
}
Add Item function
let itemName = $("#itemNameNameDrop").val();
let itemID = $("#itemID").val();
let itemPrice = $("#itemPrice").val();
let discount = $("#discount").val();
let QTYavailable = $("#QTAvailable").val();
let QTYorder = $("#QTYorder").val();
let orderID = $("#orderID").val();
let Item = new OrderItemDTO(itemID,itemName,QTYorder,itemPrice,orderID);
let itemObject={
itemID:Item.getItemID(),
name:Item.getItemName(),
QTY:Item.getItemQTY(),
Price:Item.getItemPrice(),
OrderID:Item.getOrderID()
}
ItemOrderDB.push(itemObject);
countTotal();
loadAllItemData();
$("#tableOrder>tr").dblclick(function () {
if (confirm("Are You Sure Want to Delete This Row ?"))
$(this).remove();
});
changeQTY();
clearItem();
$("#btnItemAdd").prop("disabled", true);
}
After adding item it qty value changes but when I trying to update it with set itemQTY
function give me error TypeError: ItemDB[0].setItemQTY is not a function
but in itemDTO I add it as function
I'm having problems rendering individual "li" elements through OOP approach.
I'm fetching the input from the user and using this info to create an item through a class. I'm then connecting this class to the list class responsible for rendering the list.
Once I fetch the value through a click event listener, the singleTaskRendering class isn't working. I wonder if I'm setting this up incorrectly?
const inputAccess = document.querySelector('.control').querySelector('input');
const addItemBtnAccess = document.getElementById('add-item-btn');
const toDoList = [];
const doneList = [];
//ads a li id to the item
const idGenerator = (array) => {
let n = 1;
let message = '';
for (let i = 0; i < array.length; i++) {
n += 1;
}
message = `li-${n}`;
return message;
}
class ItemTask {
constructor(itemValue, idGen) {
this.title = itemValue;
this.id = idGen;
}
}
const addItemBtnHandler = () => {
const toDoList = [];
const inputValue = inputAccess.value;
const item= new ItemTask(inputValue, idGenerator(toDoList));
toDoList.push(item);
return toDoList;
};
class singleTaskRendering {
constructor(product) {
this.product = product;
}
render() {
const titleElement = document.createElement('div');
titleElement.id = this.product.id;
titleElement.innerHTML = `
<li>
<h2>${this.product.title}</h2>
<button>Done</button>
<button>Delete</button>
</li>`;
titleElement.draggable = true;
}
}
class ItemLists {
constructor(listId, items) {
this.items = items;
this.listId = listId;
console.log(this.items, this.listId);
}
renderList() {
const renderHook = document.getElementById('hook');
const createList = document.createElement('lu');
createList.className = 'card';
createList.id = `${this.listId}-list`;
for(let item of this.items) {
const newItem = new singleTaskRendering(item);
console.log(newItem);
const itemEl = newItem.render();
console.log(itemEl, newItem);
createList.apppend(itemEl);
}
renderHook.append(createList);
}
}
const itemList = new ItemLists('active', toDoList);
itemList.renderList();
addItemBtnAccess.addEventListener('click', addItemBtnHandler);
The problem that you are having is that you call ItemLists on page load, which means it will only be processing an empty toDoList.
My solution is to rename renderList to appendItem.
Declare it at the top
Don't pass the list id and list to the constructor instead pass it to
appendItem in the clickhandler.
const inputAccess = document.querySelector('.control').querySelector('input');
const addItemBtnAccess = document.getElementById('add-item-btn');
const itemList = new ItemLists();
const toDoList = [];
const doneList = [];
//ads a li id to the item
const idGenerator = (array) => {
let n = 1;
let message = '';
for (let i = 0; i < array.length; i++) {
n += 1;
}
message = `li-${n}`;
return message;
}
class ItemTask {
constructor(itemValue, idGen) {
this.title = itemValue;
this.id = idGen;
}
}
const addItemBtnHandler = () => {
const toDoList = [];
const inputValue = inputAccess.value;
const item= new ItemTask(inputValue, idGenerator(toDoList));
itemList.appendItem('active', item);
};
class singleTaskRendering {
constructor(product) {
this.product = product;
}
render() {
const titleElement = document.createElement('div');
titleElement.id = this.product.id;
titleElement.innerHTML = `
<li>
<h2>${this.product.title}</h2>
<button>Done</button>
<button>Delete</button>
</li>`;
titleElement.draggable = true;
}
}
class ItemLists {
appendItem(listId, item) {
const renderHook = document.getElementById('hook');
const createList = document.createElement('lu');
createList.className = 'card';
createList.id = `${listId}-list`;
const newItem = new singleTaskRendering(item);
console.log(newItem);
const itemEl = newItem.render();
console.log(itemEl, newItem);
createList.apppend(itemEl);
renderHook.append(createList);
}
}
addItemBtnAccess.addEventListener('click', addItemBtnHandler);
I can't wrap my head around callback syntax, can you please help me re-write my code so that it executes in this order:
MenuBuilder.load()
MenuBuilder.draw()
Translator.load()
(in my case it executes in this order MenuBuilder.load(), Translator.load(), MenuBuilder.draw() so it doesn't do what I want)
onload.js
import MenuBuilder from "./menu-builder.js";
import Translator from "./translator.js";
var menuBuilder = new MenuBuilder();
var translator = new Translator();
menuBuilder.load();
translator.load();
menu-builder.js
"use strict"
class MenuBuilder {
constructor() {
this._nav = document.getElementsByTagName("nav")[0];
this._url = window.location.href;
}
load() {
console.log("MenuBuilder.load() start");
fetch(`/json/menu.json`)
.then((res) => res.json())
.then((jsonMenu) => {
this.draw(jsonMenu);
})
/*.catch(() => {
console.error(`Could not load ${this._lang}.json.`);
});*/
console.log("MenuBuilder.load() end");
}
draw(jsonMenu) {
console.log("MenuBuilder.draw(jsonMenu) start");
var htmlMenu = `<div id="siteTitleDiv"><p id="siteTitle" data-i18n="general.title"></p><p id="siteTitleShadow" data-i18n="general.title-shadow"></p><p id="siteSubtitle"data-i18n="general.subtitle"></p></div><ul>`;
for(var i = 0; i < jsonMenu.length; i++) {
var menuItem = jsonMenu[i];
var regexp = /http:\/\/cypher-f\.com\/(([a-z\-]*\/)?([a-z\-]*\/))?/g;
var fullPage = "something format_abc";
var match = regexp.exec(this._url);
var level_1 = match[1];
var level_2 = match[3];
var parent = match[2];
var full_suffix = match[0];
if ((parent == null) || (menuItem.parent === parent)) {
var material_icon = menuItem["material-icon"];
var href = menuItem["href"];
var i18n = menuItem["data-i18n"];
htmlMenu += `<li><i class="material-icons">${material_icon}</i></li>`;
}
}
htmlMenu += `</ul>`;
this._nav.innerHTML = htmlMenu;
console.log("MenuBuilder: nav.innerHTML");
console.log(this._nav.innerHTML);
console.log("MenuBuilder: document.elements");
console.log(document.querySelectorAll("[data-i18n]"));
console.log("MenuBuilder.draw(jsonMenu) end");
}
}
export default MenuBuilder;
translator.js
"use strict"
class Translator {
constructor() {
this._lang = this.getLanguage();
this._elements = document.querySelectorAll("[data-i18n]");
}
getLanguage() {
var lang = navigator.languages ? navigator.languages[0] : navigator.language;
return lang.substr(0, 2);
}
load(lang = null) {
console.log("Translator.load() start");
console.log("this._elements");
console.log(this._elements);
if (lang) {
this._lang = lang;
}
else {
var re = new RegExp("lang=([^;]+)");
var value = re.exec(document.cookie);
var cookieLang = (value != null) ? unescape(value[1]) : null;
if (cookieLang) {
this._lang = cookieLang;
}
}
fetch(`/i18n/${this._lang}.json`)
.then((res) => res.json())
.then((translation) => {
this.translate(translation);
})
.then(this.toggleLangTag())
.then(document.cookie = `lang=${this._lang};path=/`)
/*.catch(() => {
console.error(`Could not load ${this._lang}.json.`);
});*/
console.log("Translator.load() end");
}
translate(translation) {
console.log("Translator.load(translation) start");
this._elements.forEach((element) => {
var keys = element.dataset.i18n.split(".");
var text = keys.reduce((obj, i) => obj[i], translation);
if (text) {
element.innerHTML = text;
}
else {
element.innerHTML = `key ${keys} not found for ${this._lang}!`
}
});
console.log("Translator.load(translation) end");
}
toggleLangTag() {
if (document.documentElement.lang !== this._lang) {
document.documentElement.lang = this._lang;
}
}
switchLanguage(translator) {
var availableLang = ["en", "fr"];
var currentLangIndex = availableLang.indexOf(translator._lang);
var nextLang = availableLang[(currentLangIndex + 1)%availableLang.length];
translator.load(nextLang);
}
}
export default Translator;
I'm sorry I know this is kind of a newbie question but I haven't programmed in three years.
You're working with Promises here, so you want to stick with that paradigm. Return the promise that is returned from the fetch call, then "chain" off of that promise to call the translator.
load() {
console.log("MenuBuilder.load() start");
// The return here gives control of the promise to the caller...
return fetch(`/json/menu.json`)
.then((res) => res.json())
.then((jsonMenu) => {
this.draw(jsonMenu);
})
/*.catch(() => {
console.error(`Could not load ${this._lang}.json.`);
});*/
console.log("MenuBuilder.load() end");
}
So back in onload.js you can use the promise returned from menuBuilder.load() to call translator.load() after menuBuilder.load() is done.
import MenuBuilder from "./menu-builder.js";
import Translator from "./translator.js";
var menuBuilder = new MenuBuilder();
var translator = new Translator();
menuBuilder.load().then(() => translator.load());
I'm trying to create a User model, but I am getting:
2018-12-18 09:47:07.567 [error]: uncaughtException: Cannot set
property 'getUserId' of undefined TypeError: Cannot set property
'getUserId' of undefined
Here's the model:
var User = (userId, name, lastname) => {
this.userId = userId;
this.name = name;
this.lastname = lastname;
this.tokenizeSingle = null;
this.tokenizeFile = null;
this.detokenizeSingle = null;
this.detokenizeFile = null;
}
User.prototype.getUserId = () => {
return this.userId;
}
User.prototype.getName = () => {
return this.name;
}
User.prototype.getLastname = () => {
return this.name;
}
User.prototype.getFullName = () => {
return this.name + ' ' + this.lastname;
}
User.prototype.getTokenizeSingle = () => {
return this.tokenizeSingle;
}
User.prototype.getTokenizeFile = () => {
return this.tokenizeFile;
}
User.prototype.getDetokenizeSingle = () => {
return this.detokenizeSingle;
}
User.prototype.getDetokenizeFile = () => {
return this.detokenizeFile;
}
User.prototype.setPermissions = (tokenizeSingle, tokenizeFile, detokenizeSingle, detokenizeFile) => {
this.tokenizeSingle = tokenizeSingle || null;
this.tokenizeFile = tokenizeFile || null;
this.detokenizeSingle = detokenizeSingle || null;
this.detokenizeFile = detokenizeFile || null;
}
module.exports = User;
I am also using VS Code and it is not suggesting anything when I do: var newUser = new User(1, 'Rand', 'Fisk'); putting a dot in newUser doesn't show any of the options set in the prototype.
What am I missing?
Arrow functions doesn't have its own this-context. Change to regular functions and it should work:
function User(userId, name, lastname) {
this.userId = userId;
this.name = name;
this.lastname = lastname;
this.tokenizeSingle = null;
this.tokenizeFile = null;
this.detokenizeSingle = null;
this.detokenizeFile = null;
}
User.prototype.getUserId = function() {
return this.userId;
}
When I used getFullName, getFirstName and getLastName work ok, but I can't use set functions setFullName, setLastName, setFirstName. My code:
var Person = function(firstAndLast) {
var fn=firstAndLast.split(' ');
var fstr=fn.join(' ');
var frn=fn[0];
var lsn=fn[1];
this.getFullName=function(){return fstr;};
this.getFirstName=function(){return frn;};
this.getLastName=function(){return lsn;};
this.setFirstName=function(a){fn[0]=a;};
this.setLastName=function(b){fn[1]=b;};
this.setFullName=function(c){fn=c.split(' ');};
};
What about this:
var Person = function(firstAndLast) {
var self = this;
this.fn = firstAndLast.split(' ');
this.frn = this.fn[0];
this.lsn = this.fn[1];
this.getFullName=function(){return self.fn.join(' ');};
this.getFirstName=function(){return self.frn;};
this.getLastName=function(){return self.lsn;};
this.setFirstName=function(a){self.frn=a; self.fn[0]=a;};
this.setLastName=function(b){self.lsn=b; self.fn[1]=b;};
this.setFullName=function(c){
self.fn = c.split(' ');
self.frn = this.fn[0];
self.lsn = this.fn[1];};
};
See this fiddle
If you have a lot of Person objects, you should consider moving the getter/setter functions to the class prototype:
var Person = function(firstAndLast) {
this.fn = firstAndLast.split(' ');
this.frn = this.fn[0];
this.lsn = this.fn[1];
};
Person.prototype.getFullName = function() {
return this.fn.join(' ');
}
Person.prototype.getFirstName = function() {
return this.lsn;
}
Person.prototype.getLastName = function() {
return this.lsn;
}
Person.prototype.setFirstName = function(a) {
this.frn=a;
this.fn[0]=a;
}
Person.prototype.setLastName = function(b) {
this.lsn=b;
this.fn[1]=b;
}
Person.prototype.setFullName = function(c) {
this.fn = c.split(' ');
this.frn = this.fn[0];
this.lsn = this.fn[1];
}
See updated fiddle