AngularJS : Function only updates variable in view after an event happens - javascript

I have a simple input field :
<input id = 'input' ng-model="addMe">
that is connected to a script :
<script>
document.getElementById('input').onkeydown = function(event) {
if (event.keyCode == 13) {
angular.element(document.getElementById('input')).scope().addItem();
}
}
</script>
that is there so that whenever the user presses enter in the input field; the addItem function in AngularJS that adds the string from the input field into an array is called.
$scope.addItem = function () {
found = false;
if (!$scope.addMe) return $scope.errorText = "Please Specify an Item";
else {
angular.forEach($scope.Products, function(value, key) {
if (value.name.toUpperCase() == $scope.addMe.toUpperCase()){
$scope.cart_items.push({name : value.name, price : value.price});
$scope.grandTotal += value.price;
$scope.addMe = '';
$scope.errorText = '';
found = true;
}
});
if(!found){$scope.errorText = "Item does not exist";}
}
}
note that cart_items, and products are arrays (not directly related to the problem)
The Function addItem is called when i press enter, passing the correct variables; but the variables like errorText, grandTotal, and also the data that is supposed to be pushed into the array cart_items, only updates when i press another key, or click.
i know the function is doing what it's supposed to do; because i used console.log to debug.

Here is a sample code, change text field value, press Enter and look at the console output.
angular.module('app', []);
angular.module('app')
.controller('ExampleController', ['$scope', function($scope) {
$scope.fieldValue = "Hello";
$scope.keydown = function(event) {
if(event.key === 'Enter') {
$scope.addItem((event.srcElement || event.target).value);
}
}
$scope.addItem = function (value) {
// do something
console.log('Add item with value', value);
}
}]);
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="ExampleController">
<input type="text" ng-model="fieldValue" ng-keydown="keydown($event)">
</body>
</html>
Here is also a plunker with the code above

Related

How to save input of html textarea after refreshing the page?

I currently use the following code to save input after browser refresh.
<style>textarea, input {
width:100%;
height:50px
}
</style>
<textarea class='' id='thetext' onkeyup='saveValue(this)'/><br/><br/>
<button id='' onclick='shift()'>Shift</button><br/><br/>
<script>
var input = document.getElementById("thetext");
function shift() { input.value = input.value.toUpperCase()}
</script>
<script>document.getElementById("thetext").value = getSavedValue("thetext");
function saveValue(e){
var id = e.id;
var val = e.value;
localStorage.setItem(id, val);
}
function getSavedValue (v){
if (!localStorage.getItem(v)) {
return "";
}
return localStorage.getItem(v);
}</script>
When a user enters something in the textarea, and leaves the window, the textarea gets stored in local storage, thanks to the onkeyup event listener.
However, if the user presses the shift button and leaves the browser, the uppercase text value doesn't get stored in textarea because there's no onkeyup action after button press.
I tried various event listeners instead of onkeyup, like onblur, onunload but none of them are working. Is there any event listener which can record the actions then and there? Or any way else?
PS - This code isn't working on Stackoverflow, don't know why, however it's working on my webpage. So, Please ignore this issue.
You can just call the saveValue() method after you´ve done all your stuff you need with the input.
just update the saved value by calling the savevalue() method you defined like this input.value = input.value.replace(); input.saveValue()
Run this in your own environment.
<form>
<input name="first" placeholder="first" />
<input name="last" placeholder="last" />
</form>
<script>
const form = document.querySelector('form');
const FORM_DATA = 'FORM-DATA';
window.addEventListener('DOMContentLoaded', () => {
const fromStorage = localStorage.getItem(FORM_DATA);
if (!fromStorage) return;
const json = JSON.parse(fromStorage);
for (const input of form.querySelectorAll('input')) {
input.value = json[input.name];
}
});
form.addEventListener('keyup', () => {
const formData = Object.fromEntries([...new FormData(form)]);
localStorage.setItem(FORM_DATA, JSON.stringify(formData));
});
</script>
Here is an example that works :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Save input after refreshing</title>
</head>
<body>
<input id="myInput" type="text" />
<script>
function saveValue(inputElement) {
if (!inputElement) throw new Error('inputElement param is required');
const { id, value } = inputElement;
if (!id) throw new Error('inputElemend should have an id attribute');
localStorage.setItem(id, value);
}
function getSavedValue(inputElement) {
if (!inputElement) throw new Error('inputElement param is required');
const { id } = inputElement;
if (!id) throw new Error('inputElemend should have an id attribute');
const value = localStorage.getItem(id);
return value;
}
const input = document.querySelector('#myInput');
input.addEventListener("keyup", function(event) {
saveValue(event.target)
});
window.addEventListener('load', function() {
const value = getSavedValue(input);
input.value = value;
})
</script>
</body>
</html>

Omitting the fields with no value

I need to publish exam result from a Google sheet. The search button shows the marks obtained perfectly if roll no is provided at the box but I need to omit the fields with no value like Subject 3, 5 etc. with their textbox from the html page
Here is the sheet I'm using and the code I'm using ...
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
//Search for the id and return the array for that row
function search(id) {
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/16IH3yKJjLwM9XA0c4_BN5MVQSKh8hV7gR6_kLLfe8to/edit#gid=0");
var sheet = ss.getSheetByName("Sheet1");
var values = sheet
.getDataRange()
.getValues()
.filter(function(row) {
return row[0] == id;
});
return values[0];
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
.hidden {
display:none;
}
</style>
</head>
<body>
<input type="text" id="txtName"/>
<button id="show">SHOW</button>
<h1>FMATS</h1>
Name <input type="text" id="name"/><br>
Roll <input type="text" id="roll"/><br>
Subject 1 <input type="text" id="sub1"/><br>
Subject 2 <input type="text" id="sub2"/><br>
Subject 3 <input type="text" id="sub3"/><br>
Subject 4 <input type="text" id="sub4"/><br>
Subject 5 <input type="text" id="sub5"/><br>
</body>
<script>
//When click on show button it will run search function
window.onload = function(e){
document.getElementById('show')
.addEventListener('click', search);
}
//Get the value for txtName input and run search function in code.gs
function search() {
var txtName = document.getElementById('txtName').value;
google.script.run.withSuccessHandler(fillInfo).withFailureHandler(function (e) { console.log(e) }).search(txtName);
}
//It will run when a success response comes from search function in code.gs and updates the input with the sheet info
function fillInfo(values) {
document.getElementById('name').value = values[1];
document.getElementById('roll').value = values[0];
for (var i=0;i<values.length-2;i++) {
if (values[i+2]==null) {
toggleElement("sub"+i);
} else {
document.getElementById("sub"+i).value = values[i+2];
}
}
//rest of the code here
document.getElementById('name').value = values[1];
document.getElementById('roll').value = values[0];
document.getElementById('sub1').value = values[2];
document.getElementById('sub2').value = values[3];
document.getElementById('sub3').value = values[4];
document.getElementById('sub4').value = values[5];
document.getElementById('sub5').value = values[6];
}
</script>
</html>
I need to omit the Subject name and the text box with no value from the HTML page. And "Nothing Found" should be shown if a roll searched which is not in the table. It's not required but will be good if the Subject names come from sheet's row 1.
What should I do?
There are two ways to go about this:
Create your HTML on the server side (as #Cooper said)
Manipulate your HTML with JavaScript
To create your HTML on the server side you can use string and "write" the html automatically.
Then your functions will be something like this:
//It will run when a success response comes from search function in code.gs and updates the input with the sheet info
function fillInfo(response) {
document.getElementById("divid").innerHTML=html
});
If you absolutely want to manipulate the HTML on the client-side, you will use something like this:
function toggleElement(id) {
var td = document.getElementById(id).parentElement;
var tr = td.parentElement;
tr.classList.toggle("hidden");
}
the usage is like so:
function fillInfo(values) {
document.getElementById('name').value = values[1];
document.getElementById('roll').value = values[0];
for (var i=0;i<values.length-2;i++) {
if (values[i+2]==null) {
toggleElement("sub"+i);
} else {
document.getElementById("sub"+i).value = values[i+2];
}
}
//rest of the code here
}
and then you will have some css that does this:
.hidden {
display:none;
}
Edit:
This is how you implement the first solution:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<input type="text" id="txtName"/>
<button id="show">SHOW</button>
<h1>FMATS</h1>
<div id="dataDiv"></div>
</body>
<script>
//When click on show button it will run search function
window.onload = function(e){
document.getElementById('show')
.addEventListener('click', search);
}
//Get the value for txtName input and run search function in code.gs
function search() {
var txtName = document.getElementById('txtName').value;
google.script.run.withSuccessHandler(fillInfo).withFailureHandler(function (e) { console.log(e) }).search(txtName);
}
//It will run when a success response comes from search function in code.gs and updates the input with the sheet info
function fillInfo(values) {
console.log(values);
document.getElementById("dataDiv").innerHTML=values
}
</script>
</html>
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
//Search for the id and return the array for that row
function search(id) {
var ss = SpreadsheetApp.openByUrl("SHEETS URL");
var sheet = ss.getSheetByName("Sheet1");
var values = sheet
.getDataRange()
.getValues()
.filter(function(row) {
return row[0] == id;
})[0];
var legends = sheet.getRange(1,1,1,sheet.getMaxColumns()).getValues()[0];
return createHTML(legends, values);
}
function createHTML(legends, values) {
Logger.log(legends);
var htmlResult = "";
for (var i=0; i<values.length; i++) {
if (values[i]!=null && values[i]!=="") {
htmlResult += '<div class="field">' + (legends[i]+"").replace("Sub", "Subject ") + '<input type="text" id="sub1" value="'+values[i]+'"></div>';
}
}
return htmlResult;
}
Hope this helps!
Here's a simple example of a complete solution of your problem done mostly server side.
I like do it this way because I like to be able to use Utilities.formatString().
Server Functions:
File: aq3.gs:
function search(sObj) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Sheet1');
var rg=sh.getDataRange();
var vA=rg.getValues();
var hA=vA[0];
var dObj={dA:[]};
for(var i=1;i<vA.length;i++) {
if(vA[i][0]==sObj.roll) {
var row=vA[i];
for(var j=0;j<hA.length;j++) {
dObj[hA[j]]=row[j];
}
break;
}
}
var html="<style>input{margin:2px 5px 0 2px}</style>";
for(var i=0;i<row.length;i++) {
if(dObj[hA[i]]) {
html+=Utilities.formatString('<br /><input id="txt-%s" type="text" value="%s" /><label for="txt-%s">%s</label>',i,dObj[hA[i]],i,hA[i]);
}
}
sObj['results']=html;
return sObj;
}
Run the below function to get the dialog running. The enter the roll you wish to see in the search box and click the search button. You will get only the boxes that have data.
function launchExamResultsSearchDialog() {
var userInterface=HtmlService.createHtmlOutputFromFile('aq5');
SpreadsheetApp.getUi().showModelessDialog(userInterface, "Exam Results");
}
The html:
File: aq5.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
function search() {
var text=$('#srchtext').val();
google.script.run
.withSuccessHandler(function(sObj) {
document.getElementById("results").innerHTML=sObj.results;
})
.search({roll:text});
}
console.log("My Code");
</script>
</head>
<body>
<input type="text" id="srchtext" /><input type="button" value="Search" onClick="search();" />
<div id="results"></div>
</body>
</html>
This is what the dialog looks like:
You can just keep changing the search roll number and the dialog will replace the data with the new data. You can control the subjects by changing the headers.
Client To Server Communication
Utilities.formatString()

AngularJS input change reset

I have a simple search box. When the input box is not empty a delete button shows up to remove the text inside the box. After that the button should disappear again until i type something in the box again.
When i manually remove the text the delete box is disappearing, but when i press the delete button its not working. Do i have to use .length? I was using .value before like that: if ($(".form-control").value == '' || $(".form-control").value == $(".form-control").defaultValue) {
Thanks in advance.
a = $scope
a.change = function () {
a.limit = 6;
var x = a.search;
if (x.length == '') {
$(".form-inline").removeClass("isset");
} else {
$(".form-inline").addClass("isset");
}
};
a.clearSearch = function () {
a.search = "";
a.limit = 6;
};
html part:
<input type="search" ng-change="change()" ng-model="search" class="form-control" placeholder="Labor durchsuchen...">
<div class="icon-close" ng-click="clearSearch()"></div>
You can use ng-class for that what you are doing with JQuery:-
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.formData = {};
$scope.change = function () {
//do anything here
};
$scope.clearSearch = function () {
$scope.formData.search = "";
};
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<input type="search" ng-class="(formData.search != undefined && formData.search)?'isset':''" ng-change="change()" ng-model="formData.search" class="form-control" placeholder="Labor durchsuchen...">
<div class="icon-close" ng-click="clearSearch()"></div>
</div>
You should be able to drop the jQuery code and just use
<div class="icon-close" ng-click="clearSearch()" ng-show="search.length===0"></div>
I think you need to trigger your a.change function inside a.cleanSearch to check again if something is typed or not.
a.clearSearch = function () {
a.search = "";
a.limit = 6;
a.change()
};

how to configure autocomplete search box to delete initial characters and not call the service

my project requirement is to create an autocomplete search box which fetches data from elastic search .
i will make it simple i have a textbox on which its onChange() event fires the autocomplete webservice and fetches the data. i am using angularjs 1.6 .
<input type="text" ng-change="fetchTags ()" ng-model="autocompleteData.text"/>
javascript
$this.fetchTags = function() {
try {
//remove special chars/
$this.autoCompleteData.text = purgerFilter($this.autoCompleteData.text);
//cancel previous timer;
if (autoCompleteTimer) {
$timeout.cancel(autoCompleteTimer);
}
//to avoid late response display suggesion list
$this.autoCompleteData.hasEmitted = false;
var txt = $this.autoCompleteData.getText();
if (typeof txt !== undefined) {
//200ms debounce.
var time = 200;
if (txt.length > 0) {
autoCompleteTimer = $timeout(function() {
$this.autoCompleteData.newTag = undefined;
initiateGetTopicTagsFromWebService();
}, time);
} else {
$this.autoCompleteData.setIsVisible(false);
}
}
} catch (e) {
throw e;
}
};
everything is working fine. dont go to other function calls. my problem is in this function.
so here is whats happening :
1.if i normally start typing everything works , i get the actucal and proper response as per keywords.
2.if i delete normally . i,e from last character to first it is working fine.
3.the problem case : if i had to remove the initial characters . eg my textbox word is java script. and i decide to remove the ending a from java . the service will be called with "jav script" which i dont want. this case should not case change function to fire.
this configuration i want in my autocomplete search textbox.
Did you expect like this..
ng-change not pass $event as variable.
angular.module("myapp", [])
.controller("MyController", function($scope) {
$scope.checkWord = "";
$scope.myData = function(event) {
// console.log(event);
if(event.keyCode == 8 || event.keyCode == 46){
// console.log(event);
if(event.srcElement.selectionEnd == $scope.checkWord.length || event.srcElement.selectionStart == $scope.checkWord.length){
$scope.msg="I'm going to call the function ";
}else{
$scope.msg="I'm not going to call the function ";
}
}
}
} );
<html><head><script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script></head>
<body ng-app="myapp">
<div ng-controller="MyController" >
<input type="text" ng-model="checkWord" ng-keydown="myData($event)"/>
<br><br>{{msg}}
</div>
</body>
</html>

Shift+Enter in Textarea using AngularJS

This code shows how to use a directive to submit a form by hitting 'enter' while in a textarea. However, I would like to be able to shift+enter and go to the next line and submit the result as it is. Whenever the submission is made, it shows up in the same line. How do I submit and show the submitted text in the next line as the user intends.
<div ng-app="testApp" ng-controller="MyController">
<textarea ng-model="foo" enter-submit="submit()"></textarea><br/>
Last submitted text: {{ lastSubmitted }}<br/>
</div>
The AngularJS code:
var app = angular.module('testApp', []);
function MyController($scope) {
$scope.foo = ""
$scope.lastSubmitted = ""
$scope.submit = function() {
$scope.lastSubmitted = $scope.foo;
}
}
app.directive('enterSubmit', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('keydown', function(event) {
var code = event.keyCode || event.which;
if (code === 13) {
if (!event.shiftKey) {
event.preventDefault();
scope.$apply(attrs.enterSubmit);
}
}
});
}
}
});
What should I do?
It looks like you need to convert \n\r into <br/> then use ng-bind-html to sanitize the string.
Here is a code example
You will also have to include the angularjs sanitize js file:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular-sanitize.js"></script>

Categories