Update JS model through MVC not change - javascript

i have variables as a model, i were able to change it temporary but when try to update other values it's fetched in the controller but when try to re render it again it show the new value and retrieve the old value quickly,
the issue in updateCat func i think, also i want to pass form is object not each value alone as updated-name and updated-img.
Thanks in advance.
/* ======= Model ======= */
var model = {
currentCat: null,
cats: [
{
clickCount: 0,
name: 'Tabby',
imgSrc: 'img/434164568_fea0ad4013_z.jpg',
imgAttribution: 'https://www.flickr.com/photos/bigtallguy/434164568',
isAdmin: 0
},
{
clickCount: 0,
name: 'Tiger',
imgSrc: 'img/4154543904_6e2428c421_z.jpg',
imgAttribution: 'https://www.flickr.com/photos/xshamx/4154543904',
isAdmin: 0
},
{
clickCount: 0,
name: 'Scaredy',
imgSrc: 'img/22252709_010df3379e_z.jpg',
imgAttribution: 'https://www.flickr.com/photos/kpjas/22252709',
isAdmin: 0
},
{
clickCount: 0,
name: 'Shadow',
imgSrc: 'img/1413379559_412a540d29_z.jpg',
imgAttribution: 'https://www.flickr.com/photos/malfet/1413379559',
isAdmin: 0
},
{
clickCount: 0,
name: 'Sleepy',
imgSrc: 'img/9648464288_2516b35537_z.jpg',
imgAttribution: 'https://www.flickr.com/photos/onesharp/9648464288',
isAdmin: 0
}
]
};
/* ======= Octopus ======= */
var octopus = {
init: function () {
// set our current cat to the first one in the list
model.currentCat = model.cats[0];
// tell our views to initialize
catViewList.init();
catView.init();
},
getCurrentCat: function () {
return model.currentCat;
},
getCats: function () {
return model.cats;
},
// set the currently-selected cat to the object passed in
setCurrentCat: function (cat) {
model.currentCat = cat;
},
// increments the counter for the currently-selected cat
incrementCounter: function () {
model.currentCat.clickCount++;
catView.render();
},
// Admin mode, to edit exist cat (name, url)
showAdminForm: function () {
model.currentCat.isAdmin = 1;
catView.render();
},
updateCat: function (name, img) {
console.log(name + " ----- " + img + " before currentCat " + model.currentCat.name);
model.currentCat.name = name;
model.currentCat.imgSrc = img;
catView.render();
}
};
/* ======= View ======= */
var catView = {
init: function () {
// POINTERS
this.catElem = document.getElementById('cat-div');
this.catNameElem = document.getElementById('cat-name');
this.catCounter = document.getElementById('cat-counter');
this.catImage = document.getElementById('cat-image');
this.isAdmin = document.getElementById('show-admin');
this.adminPanel = document.getElementById('admin-panel');
this.newName = document.getElementById('updated-name');
this.newImg = document.getElementById('updated-name');
this.isAdmin.addEventListener('click', function () {
octopus.showAdminForm();
});
this.catImage.addEventListener('click', function () {
// Get count from octopus
octopus.incrementCounter();
});
this.render();
},
render: function () {
// Empty the form
// this.isAdmin.innerHTML = '';
// update the DOM elements with values from the current cat
var currentCat = octopus.getCurrentCat();
this.catCounter.textContent = currentCat.clickCount;
this.catNameElem.textContent = currentCat.name;
this.catImage.src = currentCat.imgSrc;
this.isAdmin = currentCat.isAdmin;
this.newName.textContent = currentCat.name;
this.newImg.src = currentCat.imgSrc;
this.adminPanel.addEventListener('submit', function() {
var updatedName = document.getElementById("updated-name").value;
var updatedImg = document.getElementById("updated-img").value;
// document.getElementById('cat-name') = updatedName;
octopus.updateCat(updatedName, updatedImg);
// catView.render();
});
if (this.isAdmin == 1) {
this.adminPanel.style.display = "block";
// problem here when changed and re render it fetched old name
// this.adminPanel.addEventListener('submit', function() {
// var updatedName = document.getElementById("updated-name").value;
// var updatedImg = document.getElementById("updated-img").value;
// console.log(updatedName + updatedImg);
// // document.getElementById('cat-name') = updatedName;
// octopus.updateCat(updatedName, updatedImg);
// // catView.render();
// });
} else {
this.adminPanel.style.display = "none";
}
}
};
var catViewList = {
init: function () {
// store the DOM element for easy access later
this.catListElem = document.getElementById('side_nav_item');
// render this view (update the DOM elements with the right values)
this.render();
},
render: function () {
var cat, elem, i;
// get the cats we'll be rendering from the octopus
var cats = octopus.getCats();
// empty the cat list
this.catListElem.innerHTML = '';
// loop over the cats
for (i = 0; i < cats.length; i++) {
// this is the cat we're currently looping over
cat = cats[i];
// make a new cat list item and set its text
elem = document.createElement('a');
elem.textContent = cat.name;
// on click, setCurrentCat and render the catView
// (this uses our closure-in-a-loop trick to connect the value
// of the cat variable to the click event function)
elem.addEventListener('click', (function (catCopy) {
return function () {
octopus.setCurrentCat(catCopy);
catView.render();
};
})(cat));
// finally, add the element to the list
this.catListElem.appendChild(elem);
}
}
};
octopus.init();
<!DOCTYPE html>
<html lang="en">
<head>
<link href="css/main.css" rel="stylesheet">
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"> -->
<title>Cat List </title>
</head>
<body>
<div class="main">
<div id="side_nav" class="sidenav" >
<li id="side_nav_item" class="side_nav_item"></li>
</div>
<div id="cat-div">
<h2 id="cat-name"></h2>
<div id="cat-counter"></div>
<img id="cat-image" src="" alt="cute cat">
</div>
<button id="show-admin">Admin</button>
<form id="admin-panel">
<label >Name :</label>
<input type="text" id="updated-name">
<label>Img url :</label>
<input type="text" id="updated-img">
<button id="updateCat" type="submit">Save</button>
</form>
<script src="js/model.js"></script>
</div>
</body>
</html>

I found the solution for my silly issue,
this.adminPanel.addEventListener('submit', function(evt) {
var nameToChange = document.getElementById('updated-name').value;
var imgTOChange = document.getElementById('updated-img').value;
console.log(nameToChange + imgTOChange);
octopus.updateCat(nameToChange + imgTOChange);
evt.preventDefault(); // Here is the trick
});
to close.
Thanks.

Related

Videojs - current index as variable

I have a VideoJs player that plays from a playlist.
I want to display which video number is currently playing from the playlist. Since I need the total number of videos anyway to create the playlist, I can use the defined variable there.
e.g. "Video 3 of 10".
For this I try by means of:
var test = player.currentIndex(videoList);
To pass the current number of the video into the variable.
Unfortunately without success.
var lerneinheit = "E1";
var videocounter = 26;
var videonumber= 0;
const videoList = Array.from({ length: videocounter }, (_, i) => {
return { sources: [{ src: `https://www.XXX.de/player/${lerneinheit}_${videonumber + i + 1}.mp4`, type: 'video/mp4' }], };
});
var player = videojs(document.querySelector('video'), {
inactivityTimeout: 0
});
try {
player.volume(1);
} catch (e) {}
player.playlist(videoList);
document.querySelector('.previous').addEventListener('click', function() {
player.playlist.previous();
});
document.querySelector('.next').addEventListener('click', function() {
player.playlist.next();
});
player.playlist.autoadvance(0); // play all
Array.prototype.forEach.call(document.querySelectorAll('[name=autoadvance]'), function(el) {
el.addEventListener('click', function() {
var value = document.querySelector('[name=autoadvance]:checked').value;
//alert(value);
player.playlist.autoadvance(JSON.parse(value));
});
});
/* ADD PREVIOUS */
var Button = videojs.getComponent('Button');
// Extend default
var PrevButton = videojs.extend(Button, {
//constructor: function(player, options) {
constructor: function() {
Button.apply(this, arguments);
//this.addClass('vjs-chapters-button');
this.addClass('icon-angle-left');
this.controlText("Previous");
},
handleClick: function() {
console.log('click');
player.playlist.previous();
}
});
/* ADD BUTTON */
//var Button = videojs.getComponent('Button');
// Extend default
var NextButton = videojs.extend(Button, {
//constructor: function(player, options) {
constructor: function() {
Button.apply(this, arguments);
//this.addClass('vjs-chapters-button');
this.addClass('icon-angle-right');
this.controlText("Next");
},
handleClick: function() {
console.log('click');
player.playlist.next();
}
});
videojs.registerComponent('NextButton', NextButton);
videojs.registerComponent('PrevButton', PrevButton);
player.getChild('controlBar').addChild('PrevButton', {}, 0);
player.getChild('controlBar').addChild('NextButton', {}, 2);
document.getElementById("current").innerHTML = "Von " + videocounter;
Check the API documentation:
player.curtentItem() returns the index of the current item. You'll probably want to increase this by one for display, as it is 0-based. The playlistitem event is triggered when the item has changed.

Why is my Ajax cannot save data into database? Laravel with Ajax

I am trying to save data using ajax. The ajax is inside my javascript file and passed to my controller and route. However the issue is it cannot save the data into my database.
Here is my jquery.hotspot.js file that include ajax:
(function ($) {
var defaults = {
// Object to hold the hotspot data points
data: [],
// Element tag upon which hotspot is (to be) build
tag: 'img',
// Specify mode in which the plugin is to be used
// `admin`: Allows to create hotspot from UI
// `display`: Display hotspots from `data` object
mode: 'display',
// HTML5 LocalStorage variable where hotspot data points are (will be) stored
LS_Variable: '__HotspotPlugin_LocalStorage',
// CSS class for hotspot data points
hotspotClass: 'HotspotPlugin_Hotspot',
// CSS class which is added when hotspot is to hidden
hiddenClass: 'HotspotPlugin_Hotspot_Hidden',
// Event on which the hotspot data point will show up
// allowed values: `click`, `hover`, `none`
interactivity: 'hover',
// Action button CSS classes used in `admin` mode
save_Button_Class: 'HotspotPlugin_Save',
remove_Button_Class: 'HotspotPlugin_Remove',
send_Button_Class: 'HotspotPlugin_Send',
// CSS class for hotspot data points that are yet to be saved
unsavedHotspotClass: 'HotspotPlugin_Hotspot_Unsaved',
// CSS class for overlay used in `admin` mode
hotspotOverlayClass: 'HotspotPlugin_Overlay',
// Enable `ajax` to read data directly from server
ajax: false,
ajaxOptions: { url: '' },
listenOnResize: true,
// Hotspot schema
schema: [
{
'property': 'Title',
'default': ''
},
{
'property': 'Message',
'default': ''
}
]
};
// Constructor
function Hotspot(element, options) {
var widget = this;
// Overwriting defaults with options
this.config = $.extend(true, {}, defaults, options);
this.element = element;
// `tagElement`: element for which hotspots are being done
this.tagElement = element.find(this.config.tag);
// Register event listeners
$.each(this.config, function (index, fn) {
if (typeof fn === 'function') {
widget.element.on(index + '.hotspot', function (event, err, data) {
fn(err, data);
});
}
});
if (this.config.mode != 'admin' && this.config.listenOnResize) {
$(window).on('resize', function () {
$(element).find('.' + widget.config.hotspotClass).remove();
widget.init();
});
}
if (this.config.tag !== 'img') {
widget.init();
return;
}
if (this.tagElement.prop('complete')) {
widget.init();
} else {
this.tagElement.one('load', function (event) {
widget.init();
});
}
}
Hotspot.prototype.init = function () {
this.parseData();
// Fetch data for `display` mode with `ajax` enabled
if (this.config.mode != 'admin' && this.config.ajax) {
this.fetchData();
}
// Nothing else to do here for `display` mode
if (this.config.mode != 'admin') {
return;
}
this.setupWorkspace();
};
Hotspot.prototype.createId = function () {
var id = "";
var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (var i = 0; i < 7; i++) {
id += letters.charAt(Math.floor(Math.random() * letters.length));
}
return id;
};
Hotspot.prototype.setupWorkspace = function () {
var widget = this;
// `data` array: to contain hotspot objects
var data = [];
var tHeight = $(widget.tagElement[0]).height(),
tWidth = $(widget.tagElement[0]).width(),
tOffset = widget.tagElement.offset(),
pHeight = $(widget.element[0]).height(),
pWidth = $(widget.element[0]).width(),
pOffset = widget.element.offset();
// Create overlay for the tagElement
$('<span/>', {
html: '<p>Click this Panel to Store Messages</p>'
}).css({
'height': (tHeight / pHeight) * 100 + '%',
'width': (tWidth / pWidth) * 100 + '%',
'left': (tOffset.left - pOffset.left) + 'px',
'top': (tOffset.top - pOffset.top) + 'px'
}).addClass(widget.config.hotspotOverlayClass).appendTo(widget.element);
// Handle click on overlay mask
this.element.delegate('span', 'click', function (event) {
event.preventDefault();
event.stopPropagation();
// Get coordinates
var offset = $(this).offset(),
relativeX = (event.pageX - offset.left),
relativeY = (event.pageY - offset.top);
var height = $(widget.tagElement[0]).height(),
width = $(widget.tagElement[0]).width();
var hotspot = { x: relativeX / width * 100, y: relativeY / height * 100 };
var schema = widget.config.schema;
for (var i = 0; i < schema.length; i++) {
var val = schema[i];
var fill = prompt('Please enter ' + val.property, val.default);
if (fill === null) {
return;
}
hotspot[val.property] = fill;
}
data.push(hotspot);
// Temporarily display the spot
widget.displaySpot(hotspot, true);
});
// Register admin controls
var button_id = this.createId();
$('<button/>', {
text: "Save data"
}).prop('id', ('save' + button_id)).addClass(this.config.save_Button_Class).appendTo(this.element);
$('<button/>', {
text: "Remove data"
}).prop('id', ('remove' + button_id)).addClass(this.config.remove_Button_Class).appendTo(this.element);
$(this.element).delegate('button#' + ('save' + button_id), 'click', function (event) {
event.preventDefault();
event.stopPropagation();
widget.saveData(data);
data = [];
});
$(this.element).delegate('button#' + ('remove' + button_id), 'click', function (event) {
event.preventDefault();
event.stopPropagation();
widget.removeData();
});
if (this.config.ajax) {
$('<button/>', {
text: "Send to server"
}).prop('id', ('send' + button_id)).addClass(this.config.send_Button_Class).appendTo(this.element);
$(this.element).delegate('button#' + ('send' + button_id), 'click', function (event) {
event.preventDefault();
event.stopPropagation();
widget.sendData();
});
}
};
Hotspot.prototype.fetchData = function () {
var widget = this;
// Fetch data from a server
var options = {
data: {
HotspotPlugin_mode: "Retrieve"
}
};
$.ajax($.extend({}, this.config.ajaxOptions, options))
.done(function (data) {
// Storing in localStorage
localStorage.setItem(widget.config.LS_Variable, data);
widget.parseData();
})
.fail($.noop);
};
Hotspot.prototype.parseData = function () {
var widget = this;
var data = this.config.data,
data_from_storage = localStorage.getItem(this.config.LS_Variable);
if (data_from_storage && (this.config.mode === 'admin' || !this.config.data.length)) {
data = JSON.parse(data_from_storage);
}
$.each(data, function (index, hotspot) {
widget.displaySpot(hotspot);
});
};
Hotspot.prototype.displaySpot = function (hotspot, unsaved) {
var widget = this;
var spot_html = $('<div/>');
$.each(hotspot, function (index, val) {
if (typeof val === "string") {
$('<div/>', {
html: val
}).addClass('Hotspot_' + index).appendTo(spot_html);
}
});
var height = $(this.tagElement[0]).height(),
width = $(this.tagElement[0]).width(),
offset = this.tagElement.offset(),
parent_offset = this.element.offset();
var spot = $('<div/>', {
html: spot_html
}).css({
'top': (hotspot.y * height / 100) + (offset.top - parent_offset.top) + 'px',
'left': (hotspot.x * width / 100) + (offset.left - parent_offset.left) + 'px'
}).addClass(this.config.hotspotClass).appendTo(this.element);
if (unsaved) {
spot.addClass(this.config.unsavedHotspotClass);
}
if (this.config.interactivity === 'hover') {
return;
}
// Overwrite CSS rule for `none` & `click` interactivity
spot_html.css('display', 'block');
// Initially keep hidden
if (this.config.interactivity !== 'none') {
spot_html.addClass(this.config.hiddenClass);
}
if (this.config.interactivity === 'click') {
spot.on('click', function (event) {
spot_html.toggleClass(widget.config.hiddenClass);
});
} else {
spot_html.removeClass(this.config.hiddenClass);
}
};
Hotspot.prototype.saveData = function (data) {
if (!data.length) {
return;
}
// Get previous data
var raw_data = localStorage.getItem(this.config.LS_Variable);
var hotspots = [];
if (raw_data) {
hotspots = JSON.parse(raw_data);
}
// Append to previous data
$.each(data, function (index, node) {
hotspots.push(node);
});
this.data=data;
$.ajax({
type:"POST",
url:"/store",
dataType:'json',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data:{
Title:$('#Title').val(),
Message: $('#Message').val(),
x:$('#relativeX').val(),
y: $('#relativeY').val(),
},
success: function(data){
console.log(data,d);
},
error: function(data)
{
console.log(data);
},
});
localStorage.setItem(this.config.LS_Variable, JSON.stringify(hotspots));
this.element.trigger('afterSave.hotspot', [null, hotspots]);
};
Hotspot.prototype.removeData = function () {
if (localStorage.getItem(this.config.LS_Variable) === null) {
return;
}
if (!confirm("Are you sure you wanna do everything?")) {
return;
}
localStorage.removeItem(this.config.LS_Variable);
this.element.trigger('afterRemove.hotspot', [null, 'Removed']);
};
Hotspot.prototype.sendData = function () {
if (localStorage.getItem(this.config.LS_Variable) === null || !this.config.ajax) {
return;
}
var widget = this;
var options = {
data: {
HotspotPlugin_data: localStorage.getItem(this.config.LS_Variable),
HotspotPlugin_mode: "Store"
}
};
$.ajax($.extend({}, this.config.ajaxOptions, options))
.done(function () {
widget.element.trigger('afterSend.hotspot', [null, 'Sent']);
})
.fail(function (err) {
widget.element.trigger('afterSend.hotspot', [err]);
});
};
$.fn.hotspot = function (options) {
new Hotspot(this, options);
return this;
};
}(jQuery));
Here is my route:
Route::get('hotspots','ImageController#getPin');
Route::post('store','ImageController#storePin')->name('store.storePin');
Here is my ImageController.php:
public function getPin()
{
$pin= Pin::select('Title','Message','x','y');
return hotspot::of($pin)->make(true);
}
public function storePin(Request $request)
{
$validation = Validator::make($request->all(), [
'Title' => 'required',
'Message' => 'required',
'x'=>'required',
'y'=>'required',
]);
if ($request->get('save','button_id') == "insert")
{
$pin = new Pin();
$pin->Title=$request->Title;
$pin->Message= $request->Message;
$pin->x = $request->relativeX;
$pin->y =$request->relativeY;
$pin->save();
//return Request::json($request);
}
}
Here is my hotspot.blade.php:
<!DOCTYPE html>
<html>
<head>
<title>Picomment Hotspot</title>
<link rel="stylesheet" type="text/css" href="{{ asset ('css/bootsrap.min.css') }}">
<script type="text/javascript" src="{{ asset ('js/jquery.min.js') }}"></script>
<link rel="stylesheet" type="text/css" href="{{ asset ('css/jquery.hotspot.css') }}">
<link rel="stylesheet" type="text/css" href="{{ asset ('css/style.css') }}">
<meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
<div class="container">
<div class="col-md-6" style="margin-top: 40px;">
<div id="theElement-a">
<img src="{{ asset('storage/'.$files) }}" alt="" title="">
</div>
</div>
</div>
<script type="text/javascript" src="{{ asset ('js/jquery.hotspot.js') }}"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#theElement-a").hotspot({
mode: "admin",
// uncomment
/*ajax: true,
ajaxOptions: {
'url': 'links.to.server'
},*/
interactivity: "click",
LS_Variable: "HotspotPlugin-a",
afterSave: function(err, data) {
if (err) {
console.log('Error occurred', err);
return;
}
alert('Saved');
// `data` in json format can be stored
// & passed in `display` mode for the image
localStorage.clear();
console.log(data);
},
afterRemove: function(err, message) {
if (err) {
console.log('Error occurred', err);
return;
}
alert(message);
window.location.reload();
},
afterSend: function(err, message) {
if (err) {
console.log('Error occurred', err);
return;
}
alert(message);
}
});
});
</script>
</body>
</html>

Html within Javascript

I am creating a karaoke type website, I simply want to add HTML with the words. I also want to add a break tag so some lyrics are showing on the second page.
The codepen is here:- https://codepen.io/scottYg55/pen/OJPRyXy
As you can see I have tried adding in a break tag, but this isn't outputting as HTML. I understand this, but is there a way to change this?
Can anyone help with this?
var lyricsText = [
{
"text": "Intro <br>Ding Dong Merrily on High",
"duration": 3900
}];
var player = new Vue({
el: '#player',
data: {
lyrics: {
show: false,
timer: null,
currentLine: '',
text: lyricsText,
},
song : {
progress: 0
},
audio: null,
playing: false,
playerTouched: false
},
ready: function() {
// Setup the audio element
this.audio = this.$els.audio;
// Setup time tracker updates
this.audio.addEventListener('timeupdate', this.updateTimeTracker, false);
// Setup end reset
this.audio.addEventListener('ended', this.resetPlayer, false);
},
methods: {
hideText: function() {
this.lyrics.show = !this.lyrics.show;
},
startPlayback: function() {
this.playing = true;
this.audio.volume = 0.5;
this.audio.play();
this.lyrics.show = true;
this.displayNextLine(0);
},
togglePlayback: function() {
if (!this.playerTouched) {
this.startPlayback();
this.playerTouched = true;
return;
}
this.playing = !this.playing;
if (this.audio.paused) {
this.audio.play();
this.resumeLyrics();
} else {
this.audio.pause();
this.pauseLyrics();
}
},
pauseLyrics: function() {
if (this.lyrics.timer) {
this.lyrics.timer.pause();
}
},
resumeLyrics: function() {
if (this.lyrics.timer) {
this.lyrics.timer.resume();
}
},
displayNextLine: function(line) {
var _this = this;
// Set the currentLine, which will auto display
_this.lyrics.currentLine = _this.lyrics.text[line].text;
if (_this.lyrics.text[line + 1] !== undefined) {
_this.lyrics.timer = new Timer(function() {
_this.displayNextLine(line + 1);
}, _this.lyrics.text[line].duration);
}
//else {
// _this.lyrics.currentLine = 'THE END';
//}
},
updateTimeTracker: function() {
this.song.progress = 100 * (this.audio.currentTime / this.audio.duration);
},
resetPlayer: function() {
this.playing = false;
this.playerTouched = false;
}
}
});
function Timer(callback, delay) {
var timerId;
var start;
var remaining = delay;
this.pause = function() {
window.clearTimeout(timerId);
remaining -= new Date() - start;
};
this.resume = function() {
start = new Date();
window.clearTimeout(timerId);
timerId = window.setTimeout(callback, remaining);
};
this.resume();
}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.0-rc.2/vue.js"></script>
<div class="Player" id="player">
<audio src="dd.mp3"
v-el:audio></audio>
<div class="Player__cover" #click="hideText">
<div class="Player__lyrics">
<div class="line"
v-if="lyrics.show"
v-text="lyrics.currentLine"></div>
</div>
</div>
<div class="Player__track"
:style="{ width: song.progress + '%' }"></div>
<div class="Player__controls">
<i class="icon play material-icons"
v-text="playing ? 'pause_circle_filled' : 'play_circle_filled'"
#click="togglePlayback"></i>
</div>
</div>
Try using v-html directive instead of v-text on your HTML.
<div class="line" v-if="lyrics.show" v-html="lyrics.currentLine"></div>
There are two main ways to create elements in Javascript. The first is to use createElement() function:
const div = document.createElement("div");
div.innerHTML = "I'm a div";
div.id = "myDiv";
document.body.appendChild(div);
#myDiv{
color: red;
}
The second is to use the innerHTML property on an existing element:
const div = document.getElementById("myDiv");
div.innerHTML = "<p>I'm a p tag</p>";
p{
color: green;
}
<div id="myDiv"></div>

clearing all elements from Javascript knockout observableArray. Items remain causing duplicates

I am trying to create an observableArray of "Board" objects to populate a view.
I can currently add new Board objects to the array after each timed page refresh. But instead of clearing the array and then adding new boards from the foreach loop, it just adds to the existing ones causing duplicates.
$(document).ready(function() {
refreshPage();
});
function refreshPage() {
getGames();
setTimeout(refreshPage, 10000);
console.log("Page refreshed");
};
function Board(data) {
this.gameChannel = ko.observable(data.GameChannel);
this.HomeTeamImage = ko.observable(data.HomeTeamImage);
this.HomeTeamName = ko.observable(data.HomeTeamName);
this.HomeBeerPrice = ko.observable(data.HomeBeerPrice);
this.HomeTeamArrow = ko.observable(data.HomeTeamArrow);
this.HomeBeer = ko.observable(data.HomeBeer);
this.HomeBeerAdjustedPrice = ko.observable(data.HomeBeerAdjustedPrice);
this.AwayTeamArrow = ko.observable(data.AwayTeamArrow);
this.AwayBeerPrice = ko.observable(data.AwayBeerPrice);
this.AwayTeamName = ko.observable(data.AwayTeamName);
this.AwayBeerAdjustedPrice = ko.observable(data.AwayBeerAdjustedPrice);
this.AwayBeer = ko.observable(data.AwayBeer);
this.awayTeamImage = ko.observable(data.AwayTeamImage);
this.FullScore = ko.computed(function() {
return data.HomeTeamScore + " | " + data.AwayTeamScore;
}, this);
}
function vm() {
var self = this;
self.gameCollection = ko.observableArray([]);
}
getGames = function() {
var _vm = new vm();
$.ajax({
type: "GET",
dataType: "json",
url: "/Dashboard/PopulateMonitor/",
error: errorFunc,
success: function(data) {
_vm.gameCollection = [];
$.each(data, function() {
_vm.gameCollection.push(new Board(this));
});
}
});
function errorFunc() {
alert("Error, could not load gameboards");
}
ko.applyBindings(_vm);
}
The issue appears within the getGames() function on or around the line
_vm.gameCollection = [];
I appreciate any help available. Not very well versed with Knockout.js
Every time you're calling getGames you're creating a new '_vm':
getGames = function () {
var _vm = new vm();
Move var _vm = new vm(); to
$(document).ready(function () {
var _vm = new vm(); // <-- HERE
refreshPage();
});
Some lines have to be moved too, see the snippet :
$(document).ready(function() {
_vm = new vm();
refreshPage();
});
function refreshPage() {
getGames();
setTimeout(refreshPage, 10000);
console.log("Page refreshed");
};
function Board(data) {
this.gameChannel = ko.observable(data.GameChannel);
this.HomeTeamImage = ko.observable(data.HomeTeamImage);
this.HomeTeamName = ko.observable(data.HomeTeamName);
this.HomeBeerPrice = ko.observable(data.HomeBeerPrice);
this.HomeTeamArrow = ko.observable(data.HomeTeamArrow);
this.HomeBeer = ko.observable(data.HomeBeer);
this.HomeBeerAdjustedPrice = ko.observable(data.HomeBeerAdjustedPrice);
this.AwayTeamArrow = ko.observable(data.AwayTeamArrow);
this.AwayBeerPrice = ko.observable(data.AwayBeerPrice);
this.AwayTeamName = ko.observable(data.AwayTeamName);
this.AwayBeerAdjustedPrice = ko.observable(data.AwayBeerAdjustedPrice);
this.AwayBeer = ko.observable(data.AwayBeer);
this.awayTeamImage = ko.observable(data.AwayTeamImage);
this.FullScore = ko.computed(function() {
return data.HomeTeamScore + " | " + data.AwayTeamScore;
}, this);
}
function vm() {
var self = this;
self.gameCollection = ko.observableArray([]);
ko.applyBindings(this);
}
getGames = function() {
$.ajax({
type: "GET",
dataType: "json",
// placeholder:
url: 'data:application/json;utf8,[]',
//url: "/Dashboard/PopulateMonitor/",
error: errorFunc,
success: function(data) {
_vm.gameCollection.removeAll();
$.each(data, function() {
_vm.gameCollection.push(new Board(this));
});
}
});
function errorFunc() {
alert("Error, could not load gameboards");
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
Couple of things:
You shouldn't call applyBindings more than once. So, move it outside of your setTimeout.
_vm.gameCollection = [] won't work. To clear your observableArray, use removeAll. You can also set it to an empty array like this: _vm.gameCollection([])
Also, if you want to call the same function after an interval of time, you can make use of setInterval.
Here's a minimal version of your code. Click on Run code snippet to test it out. I have created a counter variable which updates gameCollection with new data every second.
let counter = 0;
function refreshPage() {
getGames();
console.log("Page refreshed");
};
function Board(data) {
this.gameChannel = ko.observable(data.GameChannel);
}
function vm() {
var self = this;
self.gameCollection = ko.observableArray([]);
}
getGames = function() {
let data = [
{
GameChannel: `GameChannel ${++counter}`
},
{
GameChannel: `GameChannel ${++counter}`
}];
_vm.gameCollection.removeAll(); // <- Change here
data.forEach(function(item) {
_vm.gameCollection.push(new Board(item));
});
}
var _vm = new vm();
ko.applyBindings(_vm); // this needs to be only called once per page (or element)
setInterval(refreshPage, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<!-- ko foreach: gameCollection -->
<span data-bind="text: gameChannel"></span><br>
<!-- /ko -->

Error when I run a chrome plugin : Cannot read property 'addEventListener' of null

I am working on a chrome extension where keywords are populated in search from MYSQL database
my popup.js :
// UI creation
!function() {
"use strict";
/*|================================================================|*/
/*| UI creation |*/
/*|================================================================|*/
var initSectionByBgColorFromTemplate = function (sectionNodeTemplate, bgColorCode, wordGroupsDict) {
var sectionNode = sectionNodeTemplate.cloneNode(true);
var handlingIndex = 0;
var classNames = ["pure-toggle-checkbox", "pure-toggle", "color-header", "remove-group-button", "highlight-words"];
var toggleCheckbox = sectionNode.getElementsByClassName(classNames[handlingIndex])[0];
toggleCheckbox.id = classNames[handlingIndex].concat("-", bgColorCode);
toggleCheckbox.dataset.bgColor = bgColorCode;
toggleCheckbox.checked = wordGroupsDict[bgColorCode].isOn;
toggleCheckbox.addEventListener("change", wordGroupToogleHandlerFactory(wordGroupsDict));
handlingIndex++;
var toggleLabel = sectionNode.getElementsByClassName(classNames[handlingIndex])[0];
toggleLabel.id = classNames[handlingIndex].concat("-", bgColorCode);
toggleLabel.htmlFor = toggleCheckbox.id;
handlingIndex++;
var header = sectionNode.getElementsByClassName(classNames[handlingIndex])[0];
header.style.backgroundColor = "#".concat(bgColorCode);
header.textContent = bgColorCode;
handlingIndex++;
var removeButton = sectionNode.getElementsByClassName(classNames[handlingIndex])[0];
removeButton.dataset.bgColorCode = bgColorCode;
removeButton.addEventListener("click", removeGroupHandlerFactory(wordGroupsDict, sectionNode));
handlingIndex++;
var textarea = sectionNode.getElementsByClassName(classNames[handlingIndex])[0];
textarea.id = classNames[handlingIndex].concat("-", bgColorCode);
textarea.dataset.bgColor = bgColorCode;
textarea.value = wordGroupsDict[bgColorCode].words.join(" ");
textarea.addEventListener("blur", wordListChangeHandlerFactory(wordGroupsDict));
handlingIndex++;
return sectionNode;
};
var mainBlock = document.getElementById("mainBlock");
var sessionTemplate = mainBlock.getElementsByTagName("section")[0];
var newGroupForm = document.getElementById("new-group-form");
var colorInputBox = document.getElementById("new-group-color");
/*|================================================================|*/
/*| load UI data and event binding |*/
/*|================================================================|*/
var getDefaultWordGroup = function (groupName) {
return {
groupName: groupName,
isOn: false,
words: []
};
};
var createNewGroupInDict = function (wordGroupsDict, groupName) {
var wordGroup = wordGroupsDict[groupName];
if (!wordGroup) {
wordGroup = getDefaultWordGroup(groupName);
wordGroupsDict[groupName] = wordGroup;
}
};
var saveAndSendMsg = function (wordGroupsDict) {
chrome.storage.sync.set({
wordGroupsDict: wordGroupsDict
}, function () {
// console.log("wordGroupsDict saved");
});
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var messageBody = wordGroupsDict;
chrome.tabs.sendMessage(tabs[0].id, messageBody, function(response) {
// console.log(response.content);
});
});
};
var wordGroupToogleHandlerFactory = function (wordGroupsDict) {
return function (event) {
var groupName = event.target.dataset.bgColor;
var wordGroup = wordGroupsDict[groupName];
wordGroup.isOn = event.target.checked;
saveAndSendMsg(wordGroupsDict);
};
};
var wordListChangeHandlerFactory = function (wordGroupsDict) {
return function (event) {
var groupName = event.target.dataset.bgColor;
var wordGroup = wordGroupsDict[groupName];
wordGroup.words = event.target.value.match(/[^\s]+/g) || [];
saveAndSendMsg(wordGroupsDict);
};
};
var removeGroupHandlerFactory = function (wordGroupsDict, sectionNode) {
return function (event) {
sectionNode.parentElement.removeChild(sectionNode);
delete wordGroupsDict[event.target.dataset.bgColorCode];
saveAndSendMsg(wordGroupsDict);
};
};
/*|================================================================|*/
/*| load extension settings |*/
/*|================================================================|*/
chrome.storage.sync.get('wordGroupsDict', function (wordGroupsDict) {
// I just dont know how chrome.storage.sync works...
// + nothing inside, return {}
// + find the key, return {key: value}
wordGroupsDict = wordGroupsDict.wordGroupsDict || wordGroupsDict;
/*|================================================================|*/
/*| popup UI and event binding |*/
/*|================================================================|*/
// use default for 1st time
var colorGroups = Object.keys(wordGroupsDict);
if (colorGroups.length === 0) {
colorGroups = ["C72E04", "FA9507", "CACF44", "27AB99"].slice(1);
colorGroups.forEach( colorGroup => createNewGroupInDict(wordGroupsDict, colorGroup) );
}
/*
if (colorGroups.length === 0) {
var valNew = [];
var array = [];
$.ajax({
type: 'post',
url: 'http://localhost/chrome-highlight-extension-master/js/loadcolor.php',
data: {
},
success: function (response) {
var res = $.trim(response);
valNew = res.split(',');
for(var i=0;i<(valNew.length);i++){
colorGroups.push(valNew[i]);
}
colorGroups.forEach( colorGroup => createNewGroupInDict(wordGroupsDict, colorGroup) );
}
});
} */
// remove template and append initialized sections
mainBlock.removeChild(sessionTemplate);
colorGroups.forEach(function (bgc) {
mainBlock.appendChild(initSectionByBgColorFromTemplate(sessionTemplate, bgc, wordGroupsDict));
});
newGroupForm.addEventListener("submit", function (event) {
event.preventDefault();
if (colorInputBox.value && colorInputBox.value.length > 0 && colorInputBox.checkValidity()) {
console.log("submit OK");
createNewGroupInDict(wordGroupsDict, colorInputBox.value);
mainBlock.appendChild(initSectionByBgColorFromTemplate(sessionTemplate, colorInputBox.value, wordGroupsDict));
}
console.log("submit");
});
colorInputBox.addEventListener("onload", function (event) {
if (event.target.checkValidity()) {
event.target.style.backgroundColor = "#".concat(event.target.value);
} else {
event.target.style.backgroundColor = "white";
}
});
});
}();
In the above code I have some static colors
colorGroups = ["C72E04", "FA9507", "CACF44", "27AB99"];
But I want these colors from MYSQL db , so i used ajax to get colors (that part of the code has been commented )
if (colorGroups.length === 0) {
var valNew = [];
var array = [];
$.ajax({
type: 'post',
url: 'http://localhost/chrome-highlight-extension-master/js/loadcolor.php',
data: {
},
success: function (response) {
var res = $.trim(response);
valNew = res.split(',');
for(var i=0;i<(valNew.length);i++){
colorGroups.push(valNew[i]);
}
colorGroups.forEach( colorGroup => createNewGroupInDict(wordGroupsDict, colorGroup) );
}
});
}
In the ajax code i am able to fetch colors from my table but the problem is with createNewGroupInDict
this is the error I am facing
Error in response to storage.get: TypeError: Cannot read property 'addEventListener' of null
at Object.callback (chrome-extension://pgommpfcheidcagdchjjdhffidaefhaf/js/popup.js:159:16)
at chrome-extension://pgommpfcheidcagdchjjdhffidaefhaf/js/popup.js:113:22
at chrome-extension://pgommpfcheidcagdchjjdhffidaefhaf/js/popup.js:176:2
popup.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Keyword Page</title>
<link href="css/popup.css" media="screen" rel="stylesheet" type="text/css">
<link href="css/toggle.css" media="screen" rel="stylesheet" type="text/css">
</head>
<body>
<main id="mainBlock">
<div class="button-block">
<form id="new-group-form">
<input id="new-group-color" type="text" pattern="[0-9a-fA-f]{6}" title="hex color code" />
<input id="add-button" class="button" type="submit" value="+" title="add group" />
</form>
</div>
<section>
<span class="toggle">
<input type="checkbox" class="pure-toggle-checkbox" hidden />
<label class="pure-toggle flip" for="pure-toggle-">
<div class="fontawesome-remove">OFF</div>
<div class="fontawesome-ok">ON</div>
</label>
</span>
<header class="color-header">C72E04</header>
<button class="remove-group-button button">x</button>
<textarea class="highlight-words" placeholder="(separated by a space)" > </textarea>
</section>
</main>
<script src="js/popup.js"></script>
<script src="js/jquery.min.js"></script>
<script src="js/custom.js"></script>
</body>
</html>

Categories