js 'click' functionality/EventListener problem - javascript

I am trying to make an interactive button(to show a message in the console) with js, which just print a message in the console when the button is pressed. My js file is:
console.log("hello this is from cart.js")
var updateBtns = document.getElementsByClassName('update-cart')
for(var i=0; i<updateBtns.length; i++){
updateBtns[i].addEventListener('click', function(){
var productId = this.dataset.product
var action = this.dataset.action
console.log("inside loop")
//console.log('product ID: ', productId, "Action: ", action)
})
}
HTML:
<button data-product="{{ i.id }}" data-action="add" class="btn btn-outline-secondary add-btn update-cart">Add to Cart</button>
Here inside loop message does not show anytime.... the consol just show the following message:
hello this is from cart.js
DevTools failed to load SourceMap: Could not load content for chrome-extension://ndjpnladcallmjemlbaebfadecfhkepb/editor/config.js.map: HTTP error: status code 404, net::ERR_UNKNOWN_URL_SCHEME
DevTools failed to load SourceMap: Could not load content for chrome-extension://ndjpnladcallmjemlbaebfadecfhkepb/editor/content.js.map: HTTP error: status code 404, net::ERR_UNKNOWN_URL_SCHEME
How can I solve this problem?

It appears that your code works correctly when I add it to the snippet, but I think the issue might be related to how you load in your javascript code. If it is a <script> tag, could you make sure that it is included after the body tag?
So like this:
<html>
<head>...</head>
<body>
...
<script src="your-javascript-file.js"></script>
</body>
</html>
The issue could be that your script is being executed before the HTML elements are created.
console.log("hello this is from cart.js")
const dataset = {
product: [
'product-1',
'product-2',
'product-3'
],
action: (product) => { alert(product); }
}
const updateBtns = document.getElementsByClassName('update-cart')
for (let i = 0; i < updateBtns.length; i++) {
updateBtns[i].addEventListener('click', function() {
const productId = dataset.product[i]
const action = () => {
dataset.action(productId)
};
action();
//console.log('product ID: ', productId, "Action: ", action)
});
}
<button class="update-cart">1</button>
<button class="update-cart">2</button>
<button class="update-cart">3</button>

Related

error JavaScript critical error ...: Expected ')'

I am getting error below while using ajax in asp.net MVC, and I have no idea what's wrong with it!
JavaScript critical error at line 161, column 101 in
http://localhost:50474/Home/Products\n\nSCRIPT1006: Expected ')'
Here is my View:
<p class="text-center"><a class="btn btn-primary" onclick="CreateOrder(#pr.ProId)" role="button">خرید</a>
Here my Action in controller:
[HttpPost]
public ActionResult CreateOrder(Guid productId)
{
Order or = new Order();
or.Number = 1;
or.ProductId = productId;
or.SessinId = Request.UserHostAddress;
int proprice = db.Products.Where(c => c.ProId == productId).Select(c => c.Price).FirstOrDefault();
or.TotalPrice = proprice * 1;
db.Orders.Add(or);
db.SaveChanges();
int count = (db.Orders.Where(c => c.SessinId == or.SessinId).Select(c =>
c.OrderId)).Count();
Session["ShopcartCount"]= count;
db.Dispose();
return RedirectToAction("Products", "Home");
}
And here is ajax code:
<script>
function CreateOrder(productId) {
$.ajax({
url: "/Home/CreateOrder/" + productId,
type: "post"
}).done(function (result) {
$("#shopcart").html(result);
});
}
$(function () {
$("#shopcart").load("/Home/ShopCartCount");
});
</script>
Please check this way you got this error
Here working example first button your code and second button working fine.
Click here
View
<p class="text-center"><a class="btn btn-primary" onclick="CreateOrder('#pr.ProId')" role="button">خرید</a>
Like #jishan siddique posted in his answer, you need to use single quotes ' ' around your model property '#pr.ProId' like CreateOrder('#pr.ProId)' instead of CreateOrder(#pr.ProId) for the Razor view to recognise it.

How to load javascript step by step with QWebEngineView and qtwebchannel.js?

I'm setting up like a framework who use python in backend and html/css/js for frontend. My problem arrived during the loading of a QWebEngineView.
I search on the web how to establish a communication between python and javascript with QWebEngineView and I finally tried to use QtWebChannel.
So I setted up everything, and everything worked good with communication between python and javascript, but the next issue appeared:
First: i can't load javascript files directly in html with tags <script>
Second: javascript loaded randomly, i tried to load javascript from python with my_view.page().runJavascript(my_js) but it work one try on two. So sometimes jQuery load at the end, so an other part of the code doesn't work.
base.html:
<!DOCTYPE html>
<html lang="en">
<p id="log"></p>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script>
window.onerror = function (error, url, line) {
console.error("ERROR: " + error.toString());
console.error("LINE: " + line.toString());
};
function load_app(){
new QWebChannel(qt.webChannelTransport, function (channel) {
window.app = channel.objects.app;
app.load_javascript(function(ret){
console.error("load javascript: " + ret)
});
});
}
load_app();
console.error("app loaded")
</script>
{{ application_html_content | safe }}
</html>
Another part of HTML:
{% extends 'base.html' %}
{% block content %}
<div class="row">
{% for user_id, user in user_dict.items() %}
<div id="{{ user_id }}" class="col s12 m6">
<div class="card blue-grey darken-1">
<div class="card-content white-text">
<span class="card-title">Visit Card</span>
<p>{{ user.name }}</p>
</div>
<div class="card-action">
<button id="btn_del_{{ user_id }}" class="btn blue waves-effect waves-light" onclick="delete_user({{ user_id }})">Delete</button>
<button class="btn blue waves-effect waves-light" onclick="detail_user({{ user_id }})">Detail</button>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{% block javascript %}
<script>
$(document).ready(function() {
app.request_result.connect(function (result) {
if ("delete" in result) {
user_id = result.delete;
var element = document.getElementById(user_id);
element.parentNode.removeChild(element)
}
});
console.error("ready");
});
function delete_user(user_id) {
document.getElementById("btn_del_" + user_id).innerHTML = "Waiting ...";
app.request('DemoHtml:Default:delete', user_id);
}
function detail_user(user_id) {
app.path('detail_user', {"user_id": user_id});
}
</script>
{% endblock %}
load_javascript function:
JQUERY = "vendor/Resources/js/jquery.js"
MATERIALIZE = "vendor/Resources/css/materialize/js/materialize.js"
#pyqtSlot(result=str)
def load_javascript(self):
with open(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.MATERIALIZE), "r") as m_stream:
materialize_content = m_stream.read()
with open(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.JQUERY), "r") as j_stream:
jquery_content = j_stream.read()
self.template_view.view.page().runJavaScript(jquery_content)
self.template_view.view.page().runJavaScript(materialize_content)
return "ok"
As you can see, normally I must see in log error:
First: "load javascript: ok"
Second: "app loaded"
but one time one two, this is reverse like:
js: app loaded
js: ERROR: Uncaught ReferenceError: $ is not defined
js: LINE: 67
js: Uncaught ReferenceError: $ is not defined
js: load javascript: ok
Any help for this?
Thank you in advance!
I resolved my problem, thanks to #ekhumoro for trying to help me, i found an answer on this thread:
How to wait for another JS to load to proceed operation ?: https://stackoverflow.com/a/8618519/8293533
So to make it work, i change my javascript to this:
I named this file app.js
function set_app() {
try{
new QWebChannel(qt.webChannelTransport, function (channel) {
window.app_channel = channel.objects.app;
});
} catch (e) {
console.error("setting_app error: " + e)
}
}
set_app();
function request(route, args) {
let interval = 10;
window.setTimeout(function () {
if (window["app_channel"]) {
app_channel.request(route, args)
} else {
try {
set_app();
}
catch(error) {
console.error("app load error: " + error)
}
window.setTimeout(arguments.callee, interval);
}
}, interval)
}
function path(route, args) {
let interval = 10;
window.setTimeout(function () {
if (window["app_channel"]) {
app_channel.path(route, args)
} else {
try {
set_app();
}
catch(error) {
console.error("app load error: " + error)
}
window.setTimeout(arguments.callee, interval);
}
}, interval)
}
function request_result(callback) {
let interval = 10;
window.setTimeout(function () {
if (window["app_channel"]) {
app_channel.request_result.connect(callback)
} else {
try {
set_app();
}
catch(error) {
console.error("app load error: " + error)
}
window.setTimeout(arguments.callee, interval);
}
}, interval)
}
I erase my code load_javascript in python because i found the way to call js with <script> tags and qrc:/// path.
Now my html head look like this:
<!DOCTYPE html>
<html lang="en">
<p id="log"></p>
<script src="qrc:///qwebchannel.js"></script>
<script src="qrc:///app.js"></script>
<script src="qrc:///jquery.js"></script>
{{ application_html_content | safe }}
<script src="qrc:///materialize.min.js"></script>
</html>
To use qrc:///xxx.js i used QResource and .qrc, .rcc files.
This is an example of my code for those who want:
class ApplicationContainer:
SRC_QRC_PATH = "src/*Bundle/Resources/qrc/*.qrc"
SRC_RCC_PATH = "src/*Bundle/Resources/qrc/*.rcc"
VENDOR_QRC_PATH = "vendor/*Bundle/Resources/qrc/*.qrc"
VENDOR_RCC_PATH = "vendor/*Bundle/Resources/qrc/*.rcc"
def __init__(self):
self.__pyqt_application = QApplication(sys.argv)
self.__pyqt_resources = QResource()
self.set_rcc_files()
#property
def application(self):
return self.__pyqt_application
#application.setter
def application(self, new_app: QApplication):
self.__pyqt_application = new_app
def set_rcc_files(self):
qrc_files = glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.SRC_QRC_PATH))
qrc_files += glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.VENDOR_QRC_PATH))
for qrc in qrc_files:
subprocess.call(["rcc", "-binary", qrc, "-o", qrc[:-3] + "rcc"])
rcc_files = glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.SRC_RCC_PATH))
rcc_files += glob.glob(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), self.VENDOR_RCC_PATH))
for rcc in rcc_files:
self.__pyqt_resources.registerResource(rcc)
As you can see i use rcccommand, not pyrcc5
To finish, this is my .qrc file:
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file alias="jquery.js">../js/jquery.js</file>
<file alias="app.js">../js/app.js</file>
<file alias="qwebchannel.js">../js/qwebchannel.js</file>
<file alias="materialize.js">../css/materialize/js/materialize.js</file>
<file alias="materialize.css">../css/materialize/css/materialize.css</file>
</qresource>
</RCC>
I know there can be a lot of improvment and optimisation in javascript code and python code. But it works like this !
Thank's and hope i help someone too.

Load more data using vue js when page is bottom area

I tried to make my Load More data when my page scroll to the bottom. The first thing is I make a div element that I put at the end of the data loop.
<div class="products">
<p>{{ status }}</p>
<div class="product" v-for="(item, index) in items">
<div>
<div class="product-image"><img :src="item.link" alt=""></div>
</div>
<div>
<h4 class="product-title">{{ item.title }}</h4>
<p>Price : {{ price }}</p>
<button class="add-to-cart btn" #click="addItem(index)">Add Item To Cart</button>
</div>
</div>
<div id="product-list-bottom"></div>
</div>
Div element with id product-list-bottom I will detect it using scrollMonitor.js
My default data :
data: {
status: 'Empty product',
total: 0,
items: [],
cart: [],
newSearch: 'anime',
lastSearch: '',
price: STATIC_PRICE,
result: []
}
Inside mounted I detected scroll to bottom :
mounted: function() {
this.onSubmit()
var vueInstance = this
var elem = document.getElementById('product-list-bottom')
var watcher = scrollMonitor.create(elem)
watcher.enterViewport(function() {
vueInstance.appendItems()
})
}
Inside mounted I call onSubmit :
onSubmit: function() {
this.items = ''
this.status = "Searching keyword '" + this.newSearch + "' on server ..."
this.$http.get('/search/'.concat(this.newSearch))
.then(function(response) {
this.lastSearch = this.newSearch,
this.status = 'Find ' + response.data.length + ' data'
this.result = response.data
this.appendItems()
})
}
And inside onSubmit I call appendItems function :
appendItems: function() {
if(this.items.length < this.result.length) {
var start = this.items.length
var end = parseInt(this.items.length + 5)
var append = this.result.slice(start, end)
this.items = this.items.concat(append)
console.log(append)
}
}
All goes well, but when I scroll down I get an error message :
This is because this line :
this.items = this.items.concat(append)
How do I make the data on xxx change (always added five new data from the array) according to the command on the line :
var end = parseInt(this.items.length + 5)
Thanks
it seems '/search/'.concat(this.newSearch) gets evaluated into function and not an actual string value
Try this if you are using babel/webpack
this.$http.get(`/search/`${this.newSearch}`)
Or if not
this.$http.get('/search/' + this.newSearch)
I think since Vue 2.3+ or so you can get this done without any jQuery stuff or any other dependencies:
<style>
.scrollbar{
overflow-y: scroll;
//...
}
.styled-scrollbar::-webkit-scrollbar
.styled-scrollbar::-webkit-scrollbar-thumb
.styled-scrollbar::-webkit-scrollbar-track{
//styling
}
</style>
<template>
//...
<div #scroll="scroll" class="scrollbar">
<div v-for="item in items" :key="item.id">
//TODO: item content
</div
</div>
//...
</template>
<script>
{
data: {
//..
lastScrollUpdate:0
}
//..
mounted: {
scroll:function (e) {
var scrollBar=e.target;
if((scrollBar.scrollTop + scrollBar.clientHeight >= scrollBar.scrollHeight-20)){
var t=new Date().getTime();
if((t-this.lastScrollUpdate)>3000){
this.lastScrollUpdate=t;
console.log('reached end: '+scrollBar.scrollTop+' '+scrollBar.clientHeight+' '+scrollBar.scrollHeight);
//TODO: load more data
}else{
console.log("< 3sec between scoll. no update");
}
}
},
//..
}
}
</script>
You may also want to adjust this to "#scroll.passive", in order to let the scroll-function be executed parallel to the UI (https://v2.vuejs.org/v2/guide/events.html#Event-Modifiers)

Implementing a Modal Factory?

I'be been using modals as a means to communicate to users in my apps for some time now via several different front end frameworks. The logic is usually the same, defining the modal's html then rendering it via some click event.
As my applications grow, so do the number of modals I use for a user prompt or confirmation - these modals can have anything from text inputs to forms to dropdowns and so on.
My current method is to write out each separate modal in a single html file and simply call them by their IDs but I feel this is inefficient as there is plenty of duplicate boilerplate code, so I'm wondering the best way would be to create modals dynamically while keeping the code as light andclean as possible?
I've been thinking of something like a "modal factory" where you pass the content of the modal along with the height, width, styling, etc. would this be a good approach?
Thanks for any input!
Well what I do for Forms/HTML Content loaded from the server - is create a div with an ID - PartialViewDialog at the end of my page -(I load Partial Views inside a Dialog)
This one is Bootstrap 3.* based - (HTML structure based on Frontend framework
So the HTML is like this:
<body>
<!-- Other page content -->
<div class="modal fade" id="PartialViewDialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" data-modal="title"></h4>
</div>
<div class="modal-body" data-modal="content">
</div>
<div class="modal-footer" data-modal="footer">
</div>
</div>
</div>
</div>
</body>
Then in JS, I create a dialog Manager:
var MyApp = MyApp || {};
MyApp.UIHelper = MyApp.UIHelper || {};
MyApp.UIHelper.DialogManager = (function () {
"use strict";
var self = {};
self.divId = null;
self.dialog = null;
self.dialogBody = null;
self.dialogTitle = null;
self.dialogFooter = null;
self.actionUrl = "";
self.modalObject = null;
self.options = {};
function Initilize(divId, options) {
self.options = $.extend({ buttons: [] }, options);
self.divId = divId;
self.dialog = $(self.divId);
self.dialogBody = self.dialog.find('*[data-modal="content"]');
self.dialogTitle = self.dialog.find('*[data-modal="title"]');
self.dialogFooter = self.dialog.find('*[data-modal="footer"]');
self.BootgridObject = null;
};
function OpenPartialViewDialog(url, title, preprocessingFunction, postProcessingFunction) {
// Create the buttons
var options = self.GetPartialViewButtons(url, preprocessingFunction, postProcessingFunction);
// Initialise the PartialViewDialog with Buttons
Initilize('#PartialViewDialog', options);
// Set the URL for Ajax content load and Form Post
self.actionUrl = url;
// Set Dialog Title
self.dialogTitle.html(title);
// Open the PartialViewDialog
self.OpenModel();
};
// This Method creates the buttons for the Form dialog
// e.g Save, Cancel, Ok buttons
self.GetPartialViewButtons = function (url, preprocessingFunction, postProcessingFunction) {
// I only need Save and Cancel buttons always so I create them here
var buttons = {
buttons: {
// I create a save button which Posts back the Form in the Dialog
Save: {
Text: "Save",
css: "btn btn-success",
click: function () {
// Call a function before sending the Ajax request to submit form
if (preprocessingFunction) { preprocessingFunction(); }
$.ajax({
type: "POST",
url: url,
// This Dialog has a Form - which is Post back to server
data: self.dialogBody.find("form").serialize(),
success: function (response) {
// TODO: Check if response is success -
// Apply your own logic here
if (response.hasOwnProperty("IsSuccess")) {
if (response.IsSuccess) {
self.dialogBody.html("");
self.dialog.modal("hide");
// TODO: Show Success Message
// You can call another function if you want
if (postProcessingFunction) {
postProcessingFunction();
}
} else {
// If failure show Error Message
}
}
},
error: function (response) {
// If failure show Error Message
}
});
}
},
Cancel: {
Text: "Cancel",
css: "btn btn-danger",
click: function () {
self.dialogBody.html("");
self.dialogFooter.html("");
self.dialogTitle.html("");
self.dialog.modal("hide");
}
}
}
};
return buttons;
};
// dynamic creating the button objects
self.CreateButtonsHtml = function () {
var htmlButtons = [];
$.each(self.options.buttons, function (name, props) {
var tempBtn = $("<button/>", {
text: props.Text,
id: "btn_" + props.Text,
"class": props.css + "",
click: props.click
}).attr({ "style": "margin-right: 5px;" });
htmlButtons.push(tempBtn);
});
return htmlButtons;
};
// This method will load the content/form from server and assign the modal body - it will assign the buttons to the Modal Footer and Open the Dialog for user
self.OpenModel = function () {
$.ajax({
url: self.actionUrl,
type: "GET",
success: function (response) {
// Handle response from server -
// I send JSON object if there is Error in loading the content - otherwise the result is HTML
if (response.hasOwnProperty("HasErrors")) {
// Means some error has occured loading the content - you will have to apply your own logic
} else {
//Server return HTML - assign to the modal body HTML
self.dialogBody.html(response);
self.modalObject = self.dialog.modal();
// show modal
self.modalObject.show();
}
}
});
// Create the buttons in the Dialog footer
var buttons = self.CreateButtonsHtml();
self.dialogFooter.html('');
for (var i = 0; i < buttons.length; i++) {
self.dialogFooter.append(buttons[i]);
}
};
return {
OpenPartialViewDialog: OpenPartialViewDialog,
};
})();
Then whenever I need to open a dialog from the server I can call it like this:
MyApp.UIHelper.DialogManager
.OpenPartialViewDialog('/Content/Load', "My Title",
function(){alert('pre-process')},
function(){alert('post-process')}
);
Note: The PreProcess + PostProcess are called when the Save button is clicked
Here is a working/demo example which shows what the above JS does - Hope it helps
In the demo I load Dummy HTML from a div id="dummycontent"
Fiddle: https://jsfiddle.net/1L0eLazf/
Button Fiddle: https://jsfiddle.net/1L0eLazf/1/

I would like to show an error message after a user clicks on a save button if the URL they entered was invalid. Using Angular JS

I would like to show an error message AFTER a user clicks on a save button. The field that they need to complete is a URL link and it must be a valid url.. I have a working regex in place, I just have no clue how this is supposed to be done as I am very new to angular.
Here is what I have so far:
<div class="form-group">
<button type="button" class="btn btn-primary btn-block btn-lg"
ng-click="save()">
<spring:message code="journalist.social.submit.label"/>
<span class="glyphicon glyphicon-chevron-right"</span>
</button>
<span style="color: #d2232a;padding-left: 0px" class="btn"
ng-show="!canSave()">
<spring:message code="journalist.info.error.fill.all"/>
</span>
And in my scripts (The save button only works if the canSave function is true):
$scope.save = function () {
var res = [];
var files = [];
var ind = 0;
if ($scope.canSave()){ //save button should only work if the URL is valid
$scope.linkList.forEach(function (clip) {
if (!clip.link) {
return;
}
if (!CommonUtils.startsWithHttp(clip.link)) {
clip.link = CommonUtils.EMPTY_LINK + clip.link;
}
if (clip.imgData && clip.imgData.input) {
files.push({id: ind, file: clip.imgData.input, cropData: clip.imgData.cropData})
clip.logos = undefined;
}
ind = ind + 1;
res.push({
id: clip.id,
title: clip.title,
description: clip.description,
name: clip.name,
link: clip.link,
ordering: ind,
logoUrl: clip.logos ? clip.logos[clip.logoInd] : null
})
});
Journalist.updateClips(
files,
res,
$scope,
function (e) {
$scope.warningOnLocationChange = false;
Navigation.open($scope, ["journalist", "profile", "profile"]);
}
);
};
$scope.showUpload = function (clip) {
if(clip.link) {
clip.showUpload = true;
}
};
}}]
);
If you think the condition I have in my script for the save() function is not right then by all means tell me otherwise. How can I show an alert after the button is clicked? The alert shows before a URL is even entered (or as they are typing and will go away once the url is correct.) Thanks!

Categories