knockout textbox validation error - knockout-2.0

i am facing problem with knockout basic textbox validation
Here is my html
<input type="text" data-bind="value:text" />
<br />
<br />
<input type="button" data-bind="click:save" value="save" />
Here is my script
$(document).ready(function () {
ko.validation.registerExtenders();
ko.validation.configure({
registerExtenders: true,
decorateElement: true
});
var vm = ko.validatedObservable({
text: ko.observable().extend({
required: true
}),
save: function () {
debugger;
if (this.isValid()) {
alert('success');
}
else {
this.errors.showAllMessages();
alert('error');
}
}
});
ko.applyBindings(vm);
});
I have included below scripts
<script src="/Scripts/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/Scripts/knockout-2.1.0.js" type="text/javascript"></script>
<script src="/Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
<script src="/Scripts/knockout.validation.min.js" type="text/javascript"></script>
when i run this i am getting 'Undefined is not a function' at "this.isValid()"
Please help me.

I prefer this pattern to use validatedObservable - http://codepen.io/dmoojunk/pen/PwNbEL
ko.validation.registerExtenders();
ko.validation.configure({
registerExtenders: true,
decorateElement: true
});
var vm = function(){
var self = this;
self.text= ko.observable().extend({
required: true
}),
self.save= function () {
if (this.isValid()) {
alert('success');
}
else {
this.errors.showAllMessages();
alert('error');
}
}
};
var viewmodel = ko.validatedObservable(new vm())();
ko.applyBindings(viewmodel);

Related

Modifying chrome.storage.sync from popup script

I have a chrome extension with options.js and popup.js.
I have a setting that I want the user to control both from options and popup alternatively.
In options it's straight forward:
options.html
<!DOCTYPE html>
<html>
<head><title>Random options placeholder</title></head>
<body>
<label>
<input type="checkbox" id="activate">
Active
</label>
<div id="status"></div>
<button id="save">Save</button>
<script src="options.js"></script>
</body>
</html>
options.js
function save_options() {
var isActive = document.getElementById('activate').checked;
chrome.storage.sync.set({
isActive: true
}, function() {
// Update status to let user know options were saved.
var status = document.getElementById('status');
status.textContent = 'Options saved.';
setTimeout(function() {
status.textContent = '';
}, 750);
});
}
but in popup.js I don't understand how to use the chrome.storage.sync.set
to update the same shared value (isActive).
popup.js (fail)
var isActive = document.getElementById('activate').checked;
chrome.storage.sync.set({
isActive: true
});
Any suggestions?

how to add callbacks to kendo dialog actions

I've tried using the Kendo UI DialogService to call up my own component in a dialog. The issue I'm having is in using custom actions for my dialog.
Including an ng-template with custom buttons and actions somewhat defeats the purpose of using the dialogService and clutters my template with markup not directly related to it.
I've tried using code like this:
const saveAction = { text: 'Save', primary: true };
const cancelAction = { text: 'Cancel' };
const dialog = this.dialogService.open({
title: 'Edit data',
content: FormComponent,
actions: [
cancelAction,
saveAction
]
});
const form = dialog.content.instance;
form.data = data;
dialog.result.subscribe((result) => {
if (result === saveAction) {
form.save();
}
});
This will let me run a save function from my FormComponent, but won't allow me to stop the dialog from closing if the form validation is off or the save fails.
I have managed to prevent the dialog from closing after you click an action by taking a copy of the dialogs action event emitter, and replacing it with my own.
It's a hack solution to this. Hopefully Kendo will provide something better in future.
const saveAction = { text: 'Save', primary: true };
const cancelAction = { text: 'Cancel' };
const dialog = this.dialogService.open({
title: 'Edit data',
content: FormComponent,
actions: [
cancelAction,
saveAction
]
});
const form = dialog.content.instance;
form.data = data;
const actionEmitter = dialog.dialog.instance.action;
dialog.dialog.instance.action = new EventEmitter<any>();
const sub = dialog.dialog.instance.action.subscribe(action => {
// Perform any check here based on whether you want the dialog to close or not
if(form.validate()) {
// Only call this if you want the dialog to close
actionEmitter.emit(action);
}
});
dialog.result.subscribe((result) => {
sub.unsubscribe(); // clean up
if (result === saveAction) {
form.save();
}
});
You can use method 'setOptions', but I don't know why this method doesn't exist in Telerik Document: https://docs.telerik.com/kendo-ui/api/javascript/ui/dialog
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.2.619/styles/kendo.common.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.2.619/styles/kendo.rtl.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.2.619/styles/kendo.default.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.2.619/styles/kendo.mobile.all.min.css">
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2019.2.619/js/angular.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2019.2.619/js/jszip.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2019.2.619/js/kendo.all.min.js"></script>
</head>
<body>
<div id="dialog"></div>
<input type="button" value="show dialog" onclick="showDialog()" />
<script>
$("#dialog").kendoDialog({
visible: false,
content: 'first content',
actions: [{
text: "OK",
action: function (e) {
return false;
},
primary: true
}, {
text: "Cancel"
}]
});
function showDialog() {
var dialog = $("#dialog").data("kendoDialog");
dialog.setOptions({
closable: false,
content: 're-open content',
actions: [{
text: 'test1',
primary: true
},
{
text: 'test2'
}
]
});
dialog.open();
console.log(dialog.options.actions)
}
</script>
</body>
</html>

How to add img src attribute with VueJs

In my NodeJs route, I have the following:
router.get('/list/:id', function(req, res, next) {
request("http://localhost:3000/api/journal/" + req.params.id, function(error, response, body) {
var json = JSON.parse(body);
res.render('listdetail', { title: 'Journal', data: json });
});
});
The data is a json object containing all my screen fields. One of the fields is a base64 presentation of an image.
Then, in my List Detail html I have the following:
<div id="app">
<img class="materialboxed" src="{{data.base64Image}}" width="200">
</div>
This is surely not working... How can I add to the src attribute the base64 information that was sent by NodeJS?
I tried also the following:
<img class="materialboxed" :src=imagebase64Source width="200">
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
imagebase64Source: {{data.base64Image}}
}
})
</script>
But it obviously does not work
Thanks
EDIT:
Strange, it's working now!
Here's what I've done:
<img class="materialboxed" src="{{ data.base64Image }}" width="200">
The only difference I can see is the spacing between the mustache.
Thanks to all who helped.
You can do it simply like this:
<template>
<div>
<img :src="image"/>
</div>
</template>
<script>
module.exports = {
data: function() {
return {
image: //your b64 string there
};
}
};
</script>
Pay attention by the way, depending on what you have on your string, you may have to add a header to the raw string.
<template>
<div>
<img :src="imgWithHeader"/>
</div>
</template>
<script>
module.exports = {
data: function() {
return {
image: //your b64 string there
};
},
computed: {
imgWithHeader() {
return 'data:' + MIMETypeOfTheImage + ';base64,' + this.image;
}
}
};
</script>
Of course you should figure out what is the type of the image, in this case.
I think the method you tried should work if the syntax is corrected
So this:
<img class="materialboxed" :src=imagebase64Source width="200">
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
imagebase64Source: {{data.base64Image}}
}
})
</script>
should be changed to this:
<img class="materialboxed" :src="imagebase64Source" width="200">
<script type="text/javascript">
var app = new Vue({
el: '#app',
data () {
return {
imagebase64Source: data.base64Image,
}
}
})
</script>

ReactJS event does not fire when Semantic-UI css is loaded

I recently began learning ReactJS and tried to implement a simple multiple choice question. Everything works fine if I leave styles out, but if I include semantic-ui's css file, then things stop working properly. Specifically, my onChange handler in MultipleChoiceAnswer is never called, but the other lifecycle functions still work properly. Code is below.
Question.js
var React = require('react');
var MultipleChoiceAnswer = React.createClass({
getInitialState: function () {
return {isChecked: false};
},
componentDidMount: function () {
console.log('answer mounted');
},
handleChange: function (event) {
console.log('state changed');
this.setState({isChecked: event.target.checked});
},
render: function () {
var self = this;
return (
React.createElement('div', {className: 'field'},
React.createElement('div', {className: 'ui radio checkbox'},
React.createElement('input', {type:'radio', name:'answer_', defaultValue:self.props.data.text, defaultChecked: self.state.isChecked, onChange:self.handleChange}),
React.createElement('label', null, self.props.data.text)))
);
}
});
var MultipleChoiceQuestion = React.createClass({
handleChange: function (event, selected) {
console.log('stuff changed');
},
getInitialState: function() {
return {};
},
componentDidMount: function () {
console.log('Question mounted');
},
handleClick: function(event) {
console.log('click!');
this.setState({});
},
render: function () {
var rows = this.props.data.map(function (item) {
return (
React.createElement(MultipleChoiceAnswer, {key:item.id, data:item})
);
});
return (
React.createElement('div', {className: 'ui form', onSubmit: this._onSubmit},
React.createElement('h3', null, 'What is the correct answer?'),
React.createElement('div', {className: 'grouped fields'}, rows),
React.createElement('input', {type:'button', value:'Submit now', onClick:this._onSubmit}))
)
},
_onSubmit: function() {
console.log('Submitted');
}
});
module.exports.MultipleChoiceQuestion = MultipleChoiceQuestion ;
Index.ejs
<!doctype html>
<html>
<head>
<title>React Isomorphic Server Side Rendering Example</title>
<!-- <link href='/semantic.min.css' rel="stylesheet" type="text/css">-->
</head>
<body>
<h1 id="main-title">React Isomorphic Server Side Rendering Example</h1>
<div id="react-main-mount">
<%- reactOutput %>
</div>
<!-- comment out main.js to see server side rendering -->
<script src="/jquery-2.1.3.min.js"></script>
<script src="/semantic.min.js"></script>
<script>
$(document).ready(function () {
$('.ui.checkbox').checkbox();
});
</script>
<script src="/main.js"></script>
</body>
</html>
Can you please help? It's stupid that I can't get a simple radio button to work >.>
I got it to work. I removed the change handler to the question component instead of the answer component and gave each input in the answer component a defaultChecked and defaultValue propery. Those two properties were the key things that made it work.
var React = require('react');
var MultipleChoiceAnswer = React.createClass({
getInitialState: function () {
return {isChecked: false};
},
componentDidMount: function () {
console.log('answer mounted');
},
render: function () {
return (
React.createElement('div', {className: 'field'},
React.createElement('div', {className: 'ui radio checkbox'},
React.createElement('input', {type:'radio', name:'answer', id:'answer_' + this.props.id, defaultChecked:false, defaultValue:this.props.data.text}),
React.createElement('label', {htmlFor:'answer_' + this.props.id}, this.props.data.text)))
);
}
});
var MultipleChoice = React.createClass({
handleChange: function (event, selected) {
console.log('Selected value: ', event.target.value);
},
getInitialState: function() {
return {};
},
componentDidMount: function () {
console.log('Question mounted');
},
render: function () {
var rows = this.props.data.answers.map(function (item) {
return (
React.createElement(MultipleChoiceAnswer, {key:item.id, data:item, id:item.id})
);
});
return (
React.createElement('div', {className: 'ui form', onSubmit: this._onSubmit},
React.createElement('div', {className: 'grouped fields', onChange:this.handleChange},
React.createElement('label', null, 'What is the correct answer?'),
rows),
React.createElement('input', {type:'button', value:'Submit now', onClick:this._onSubmit}))
)
},
_onSubmit: function() {
console.log('Submitted');
}
});
module.exports.MultipleChoice = MultipleChoice;

How to add action buttons in a popup and navigate to a website in chrome extension?

I am in need to a show 2 pop ups on 2 different situation.Presently I am checking a server file and storing its credentials in a localStorage.Each time when the user clicks on the extension,it should check if the localStorage is empty or not.If it is empty,then a pop up should be seen and asks for his username.this is stored in localstorage.Next time when the user clicks on the icon,the localstorage is not empty,so it should show another pop up showind a field for username with 2 buttons namely 'change settings' and 'go to website'.When the user clicks on change settings,again the popup shuuld appear asking user name.If he clicks go to website,it should navigate to a website.How can this be done?please help me.I have tried button the button is not working.And also the 2nd pop up is always shown only on reloading the extension.Please help me.
Here is my background.js
here is my updated popup.js
window.addEventListener('DOMContentLoaded', function() {
var divLoading = document.querySelector('div#loadingContainer');
var divSettings = document.querySelector('div#settingsContainer');
var divLoggedIn = document.querySelector('div#loggedInContainer');
var divChange = document.querySelector('div#settingsChange');
var user1 = divSettings.querySelector('input#user1');
var form = divSettings.querySelector('form#userinfo');
var user2 = divLoggedIn.querySelector('span#user2');
var change = divLoggedIn.querySelector('input#change');
var calpine = divLoggedIn.querySelector('input#calpine');
var user3 = divChange.querySelector('input#user3');
var form3 = divChange.querySelector('input#changeset');
var cancel = divChange.querySelector('input#emailcancel');
var user = localStorage.username;
if (user) {
// user1.value = user2.value = user;
user1.value = user2.textContent = user;
user3.value = user;
divLoggedIn.style.display = 'block';
divSettings.style.display = 'none';
divChange.style.display = 'none';
} else {
divSettings.style.display = 'block';
divChange.style.display = 'none';
divLoggedIn.style.display = 'none';
user1.focus();
user1.select();
}
divLoading.style.display = 'none';
form.addEventListener('submit', function(evt) {
evt.preventDefault();
var userStr = user1.value;
chrome.runtime.getBackgroundPage(function(bgPage) {
bgPage.login(userStr);
});
window.close();
});
form3.addEventListener('click', function() {
var userStr = user3.value;
chrome.runtime.getBackgroundPage(function(bgPage) {
bgPage.login(userStr);
});
window.close();
});
change.addEventListener('click', function(evt) {
divLoggedIn.style.display = 'none';
divSettings.style.display = 'none';
divChange.style.display = 'block';
user3.focus();
user3.select();
});
cancel.addEventListener('click', function() {
divLoggedIn.style.display = 'block';
divSettings.style.display = 'none';
divChange.style.display = 'none';
user3.focus();
user3.select();
});
calpine.addEventListener('click', function() {
chrome.tabs.create({ url: 'http://www.calpinemate.com/' });
});
});
I have made some changed as i was asked to do so.I have added a new div named divchange.
here is my updated userinfo.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="popbak.js"></script>
</head>
<body>
<div id="loadingContainer"></div>
<div id="settingsContainer">
<b>Please Enter your Email ID/Employee Code</b>
<br />
<br />
<form id="userinfo">
<table>
<tr><td> <label for="user">Email/Employee Code:</label></td>
<td> <input type="text" id="user1" required /></td></tr>
<tr><td> <input type="submit" id="login" value="Log In" /></td></tr>
</table>
</form>
</div>
<div id="settingsChange">
<b>Please Enter your Email ID/Employee Code</b>
<br />
<br />
<table>
<tr><td><label for="user">Email/Employee Code:</label></td>
<td><input type="text" id="user3" required /></td></tr>
<tr><td><input type="button" id="emailchange" value="Change" /></td>
<td><input type="button" id="emailcancel" value="Cancel" /></td> </tr>
</table>
</div>
<div id="loggedInContainer">
<table>
<tr><td> <label for="user">Email/Employee Code:</label></td>
<!-- <input type="text" id="user2" readonly /> -->
<td><span id="user2"></span></td> </tr>
<br />
<tr><td><input type="button" id="calpine" value="Go to Calpinemate"/></td>
<td><input type="button" id="change" value="Change Settings"/></td></tr>
</table>
</div>
</body>
</html>
here is my bgpage.login()
function login(useremail){
if(!useremail)
{
alert('Please enter your Email/Employee code'); //this is not working
return;
}
var urlPrefix = 'http://www.calpinemate.com/employees/attendanceStatus/';
var urlSuffix = '/3';
var req1 = new XMLHttpRequest();
req1.addEventListener("readystatechange", function() {
if (req1.readyState == 4) {
if (req1.status == 200) {
var item=req1.responseText;
if(item==1){
localStorage.username=useremail;
updateIcon();
}
else
{
alert('Please enter a valid Email/employee code');
updateIcon();
}
}
else {
alert("ERROR: status code " + req1.status);
}
}
});
var url = urlPrefix + encodeURIComponent(useremail) + urlSuffix;
req1.open("GET", url);
req1.send(null);
}
Here is my background.js
var myNotificationID = null;
var oldChromeVersion = !chrome.runtime;
setInterval(function() {
updateIcon();
}, 1000);
function getGmailUrl() {
return "http://calpinemate.com/";
}
function isGmailUrl(url) {
return url.indexOf(getGmailUrl()) == 0;
}
function onInit() {
updateIcon();
if (!oldChromeVersion) {
chrome.alarms.create('watchdog',{periodInMinutes:5,delayInMinutes: 0});
}
}
function onAlarm(alarm) {
if (alarm && alarm.name == 'watchdog') {
onWatchdog();
}
else {
updateIcon();
}
function onWatchdog() {
chrome.alarms.get('refresh', function(alarm) {
if (alarm) {
console.log('Refresh alarm exists. Yay.');
}
else {
updateIcon();
}
});
}
if (oldChromeVersion) {
updateIcon();
onInit();
}
else {
chrome.runtime.onInstalled.addListener(onInit);
chrome.alarms.onAlarm.addListener(onAlarm);
}
function updateIcon(){
if(localStorage.username){
var urlPrefix = 'http://www.calpinemate.com/employees/attendanceStatus/';
var urlSuffix = '/2';
var req = new XMLHttpRequest();
req.addEventListener("readystatechange", function() {
if (req.readyState == 4) {
if (req.status == 200) {
var item=req.responseText;
if(item==1){
chrome.browserAction.setIcon({path:"calpine_logged_in.png"});
chrome.browserAction.setBadgeBackgroundColor({color:[190, 190, 190, 230]});
chrome.browserAction.setBadgeText({text:""});
chrome.notifications.clear('id1', function(){});
}
else{
chrome.browserAction.setIcon({path:"calpine_not_logged_in.png"});
chrome.browserAction.setBadgeBackgroundColor({color:[190, 190, 190, 230]});
chrome.browserAction.setBadgeText({text:""});
chrome.notifications.create(
'id1',{
type: 'basic',
iconUrl: '/calpine_not_logged_in.png',
title: 'Warning : Attendance',
message: 'Please mark your Attendance !',
buttons: [{ title: 'Mark',
iconUrl: '/tick.jpg'
},{ title: 'Ignore',
iconUrl: '/cross.jpg'}],
priority: 0},
function(id) { myNotificationID = id;}
);
}
}
else {
alert("ERROR: status code " + req.status);
}
}
});
var url = urlPrefix + encodeURIComponent(localStorage.username) + urlSuffix;
req.open("GET", url);
req.send(null);
}
}
onInit();
First of all, the localStorage of the background-page and that of the popup are not the same objects. Besides, each time the popup is shown, it is loaded anew, thus the localStorage is empty.
UPDATE: Thx to rsanchez's comment, I correct my mistake: the popup shares the localStorage object of the extension (which is the same as the one of the background-page).
You should use the localStorage of the background-page. (Keep in mind this works only because you have a persistent background-page !)
The simplest (and most reliable) way is to have a single popup with two different divs (one for entering credentials and one for logging in) and display only one at a time.
E.g.:
1) Remove any chrome.browserAction.onClicked... listener from the background-page (it won't hurt leaving it there as it will never be triggered, but it will confuse you in the future).
2) Declare a popup in your manifest (if you don't have already done do):
<pre>
...
"browser_action": {
...
"default_popup": "popup.html"
},
...
</pre>
3). Create a file named popup.html with the following code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
<div id="loadingContainer"><h3>Loading...</h3></div>
<div id="settingsContainer" style="display:none;">
<b>Enter your Email ID/Employee Code</b>
<br />
<br />
<form id="userinfo">
<label for="user">Email/Employee Code:</label>
<input type="text" id="user1" required />
<input type="submit" id="login" value="Log In" />
</form>
</div>
<div id="loggedInContainer" style="display:none;">
<label for="user">Email/Employee Code:</label>
<!--<input type="text" id="user2" readonly />-->
<span id="user2"></span>
<br />
<input type="button" id="calpine" value="Go to Calpinemate"/>
<input type="button" id="change" value="Change Settings"/>
</div>
</body>
</html>
</pre>
4) Create a file named popup.js with the following code:
window.addEventListener('DOMContentLoaded', function() {
/* Container divs */
var divLoading = document.querySelector('div#loadingContainer');
var divSettings = document.querySelector('div#settingsContainer');
var divLoggedIn = document.querySelector('div#loggedInContainer');
/* Settings-container fields */
var user1 = divSettings.querySelector('input#user1');
var form = divSettings.querySelector('form#userinfo');
/* LoggedIn-container fields */
//var user2 = divLoggedIn.querySelector('input#user2');
var user2 = divLoggedIn.querySelector('span#user2');
var change = divLoggedIn.querySelector('input#change');
var calpine = divLoggedIn.querySelector('input#calpine');
/* Query the extension's localStorage
* in order to decide which DIV to show */
var user = localStorage.username;
if (user) {
/* 'Username' is set: Show the LoggedIn-container
* (after updating the value of the (readonly) '#user' field) */
//user1.value = user2.value = user;
user1.value = user2.textContent = user;
divLoggedIn.style.display = 'block';
} else {
/* 'Username' is not set: Show the Settings-container */
divSettings.style.display = 'block';
user1.focus();
user1.select();
}
divLoading.style.display = 'none';
/* Listener for '#userinfo' form */
form.addEventListener('submit', function(evt) {
evt.preventDefault();
var userStr = user1.value;
chrome.runtime.getBackgroundPage(function(bgPage) {
bgPage.login(userStr);
});
window.close();
});
/* Listener for '#change' button */
change.addEventListener('click', function(evt) {
divLoggedIn.style.display = 'none';
divSettings.style.display = 'block';
user1.focus();
user1.select();
});
/* Listener for '#calpine' button */
calpine.addEventListener('click', function() {
chrome.tabs.create({ url: 'https://your.domain.goes/here' });
});
});

Resources