I am studying Angular. I am making an application: an user choose from one html selection, then fill two input fields. After this, the user press Update and the barcode script generates the code image with 3 parameters: the first select and the two input. ( these three are separated by some spaces ). So far, no problem.
I've added the button for add new forms, and the json array save the input correctly. I wanted to generate a barcode for each compiled form. How can i do? This is an easy example of what i am doing:
http://plnkr.co/edit/hxZb6g9tkwN0zpRmOMjw?p=preview
at the end of html you can find the script of barcode:
<div class="ean">
<img id="barcodeImage" style="border: solid 1px black;"/>
<script type="text/javascript">
function updateBarcode()
{
var barcode = new bytescoutbarcode128();
var space= " ";
var value = document.getElementById("barcodeValue").value;
var value1 = document.getElementById("barcodeValue1").value;
var value2 = document.getElementById("barcodeValue2").value;
barcode.valueSet(value + space + value1 + space + value2);
barcode.setMargins(5, 5, 5, 5);
barcode.setBarWidth(2);
var width = barcode.getMinWidth();
barcode.setSize(width, 100);
var barcodeImage = document.getElementById('barcodeImage');
barcodeImage.src = barcode.exportToBase64(width, 100, 0);
}
</script>
You're definitly not doing this the angular-way : mixing angular code and plein javascript, as you're doing, is generally not a good idea. It would be a good idea to write an custom directive which bundle your barcode library.
Anyway, your updateBarcode function is getting its values directly from the html input fields (eg. document.getElementById("barcodeValue").value) and writing directly its results into the DOM. With angular you may not manipulate the DOM directly but use your controller's scope (eg. $scope.foods).
To fix this, you can move your updateBarcode function into your angular controller and create an html container four your resulting images, achieving something like this :
app.controller('ProductController', function($scope,$http) {
$scope.foods = [ { ... } ]
...
$scope.updateBarcode = function() {
...
angular.forEach($scope.foods, function(food) {
var value = food.selectproduct;
var value1 = food.Quantity1;
var value2 = food.Quantity2;
...
// here, i'm not sure the following code will work as it is. If not, you'd better use a directive and angular.element()
// but here is the general concept...
var barcodeContainer = document.getElementById('barcodeContainer');
var img = document.createElement("img");
img.src = barcode.exportToBase64(width, 100, 0);
barcodeContainer.appendChild(img)
}
}
}
Then change your html accordingly :
<input type="button" value="Update" onclick="updateBarcode()" />
to:
<input type="button" value="Update" ng-click="updateBarcode()" />
and
<img id="barcodeImage" style="border: solid 1px black;"/>
to:
<style type="text/css">
#barcodeContainer img {
border: solid 1px black;
}
</style>
<div id="barcodeContainer">
</div>
You should use the Angular way! Don't mix plain Javascript with Angular. This will be misleading. BTW. You shouldn't use ids in a list. Id's should be unique. The function document.getElementById will always return the first element it finds with this id. This way you'll never find the other elements.
Create the barcode for each item in the list and angular will bind the generated barcode to the image.
$scope.updateBarcode = function(food) {
var barcode = new bytescoutbarcode128();
barcode.valueSet([food.selectedproduct,food.Quantity1,food.Quantity2].join(" "));
barcode.setMargins(5, 5, 5, 5);
barcode.setBarWidth(2);
var width = barcode.getMinWidth();
barcode.setSize(width, 100);
food.barcodeSrc = barcode.exportToBase64(width, 100, 0);
};
http://plnkr.co/edit/4scoibxyZ1EgJiRMex1V?p=preview
Have a look at this plukr (forked from your sample), and use class instead of id:
<img class="xxx" code-index="{{$index}}">
Basically what you need is to put the image inside the repeater and find a way to address it.
But since you are learning angular, why not turn everything into a single component and use ng-click instead of onclick?
Related
I'm working on a script to simulate a page change in a Questionnaire I'm building. I figured maybe I could use a bunch of "if" statements to house all the logic but it's not working right, before I go and create separate functions I'd like to know if it's possible to put them all in one single function.
So far this is the script
function pageChange(){
var chng1 = document.getElementById("p1next");
var chng2a = document.getElementById("p2back");
var chng2b = document.getElementById("p2next");
var chng3a = document.getElementById("p3back");
var chng3b = document.getElementById("p3next");
var pg1 = document.getElementById("page01");
var pg2 = document.getElementById("page02");
var pg3 = document.getElementById("page03");
if (chng1.click){
pg1.style.display="none";
pg2.style.display="block";
}
if (chng2a.click){
pg1.style.display="block";
pg2.style.display="none";
}
the "p1next, p2back, p2next etc." are IDs I gave the buttons on the pages, which I have in DIVs that I respectively named "page01, page02, page03 etc."
Without the 2nd if statement the script works exactly how I want it, it changes the display for "page01" to none and the div for "page02" to block. When I add the second if statement it doesn't work.
The reason I want to do it like this rather than making actual pages is because I don't want the data to get lost when they load another page. Am I on the right track or do I need to create a new function for each page?
Not exactly on the right track, you should use onclick events, instead of if (x.click) like this:
var chng1 = document.getElementById("p1next");
var pg1 = document.getElementById("page01");
var pg2 = document.getElementById("page02");
// Events
chng1.onclick = function(){
pg1.style.display="none";
pg2.style.display="block";
};
This will save your function until the element is clicked and then execute that function. In your case, it is executed on page load, and at that moment the user is not clicking anything.
Why not try something like this:
HTML:
<div class="page" data-pg="1">...</div>
<div class="page" data-pg="2">...</div>
<div class="page" data-pg="3">...</div>
<input id="btnPrev" type="button" value="Prev" />
<input id="btnNext" type="button" value="Next" />
jQuery:
var pageNum = 1;
$(document).ready(function () {
$("#btnPrev").on("click", function () { ChangePage(-1); });
$("#btnNext").on("click", function () { ChangePage(1); });
ChangePage(0);
});
function ChangePage(p) {
$(".page").hide();
pageNum += p;
$(".page[data-pg='" + p + "']").show();
$("#btnPrev").removeAttr("disabled");
$("#btnNext").removeAttr("disabled");
if (pageNum === 1) $("#btnPrev").attr("disabled", "disabled");
if (pageNum === $(".page").length) $("#btnNext").attr("disabled", "disabled");
}
That way you can easily grow your number of pages without changing the script. My apologies by the way for doing this in jQuery.
Update:
Have a lot of time on my hands today and have not coded for while using vanilla Javascript. Here's the version of the code using plain js: https://jsfiddle.net/hhnbz9p2/
I'm building a UI library in JS that can, without relying on any CSS stylesheets, create UI components, stylised from code. So far, it's been quite easy, with exception of styling different control states (such as input:focus one).
Code that I use to create input field:
function newInput()
{
var ctr = docmuent.createElement("input");
ctr.setAttribute("type","text");
ctr.setAttribute("value", some-default-value);
ctr.style.fontFamily = "sans-serif,helvetica,verdana";
/* some font setup here, like color, bold etc... */
ctr.style.width = "256px";
ctr.style.height = "32px";
return ctr;
}
Styling it for default state is easy. However I am unsure how to set style for states such as focused, disabled or not-editable.
If I'd be having CSS stylesheets included in the project that would be easily sorted out. However I can't have any CSS files included, it must be pure JS.
Does anyone know how to set style for an input field state (eg. input:focus) straight from JS code?
No JQuery please :-) Just straight-up JS.
Thanks in advance!
You would need to add an event listener to the element in order to change the style of it. Here is a very basic example.
var input = document.getElementById("something");
input.addEventListener("focus", function () {
this.style.backgroundColor = "red";
});
<input type="text" id="something" />
Other alternative would be to build a stylesheet for the page.
Something like this:
var styles='input:focus {background-color:red}';
var styleTag=document.createElement('style');
if (styleTag.styleSheet)
styleTag.styleSheet.cssText=styles;
else
styleTag.appendChild(document.createTextNode(styles));
document.getElementsByTagName('head')[0].appendChild(styleTag);
This way you will have clean separation of css styles from the scripts and so the better maintenance.
Use CSS Variables if possible
It's 2022 and there are more simple solutions to this problem than adding event listeners all over the place that may never get cleaned up.
Instead if you have control over the CSS simply do this in your CSS:
.my-class {
--focusHeight: 32px;
--focusWidth: 256px;
}
.my-class:focus {
height: var(--focusHeight);
width: var(--focusWidth);
}
Then in your JavaScript it's as simple as using setProperty to update the variables:
const el = document.getElementById('elementId');
el.style.setProperty('--focusHeight', newFocusHeight);
el.style.setProperty('--focusWidth', newFocusWidth);
At first, create your input:
<input type="text" id="myElementID" />
Then add the javascript the following javascript:
const element = document.getElementById("myElementID");
// Add a box shadow on focus
element.addEventListener("focus", (e) => {
e.target.style.boxShadow = "0 0 0 3px #006bff40";
});
// Remove the box shadow when the user doesn't focus anymore
element.addEventListener("blur", (e) => {
e.target.style.boxShadow = "";
});
A quick oneliner, which dynamically appends a style tag to the
body.
document.body.innerHTML += '<style>#foo:focus {background-color:gold}</style>'
<input id="foo"/>
let input = document.querySelector(".input-text");
let label = document.querySelector('.fields-label');
input.addEventListener('focus', function(e){
label.classList.add('is-active');
})
input.addEventListener('blur', function(e){
if(input.value === "") {
label.classList.remove('is-active');
}
})
label.is-active{
color:red;
}
<div class="input-fields">
<label class="fields-label">Last Name</label>
<input type="text" class="input-text">
</div>
Pretty sure I know the solution... would write .on('change','load', function(){}
correct? <-- Tested didn't work? so I am up to your solutions :)
Sushanth -- && adeneo both came up with great solutions, this is a good lesson in optimizing code... It's gonna be hard to choose which answer to go with, but I know this is going to help me rethink how I write... I dont know what I do without this forum, id have to learn this stuff in college.
This is purely a question out of curiosity and bettering my skills, as well as giving you guys a chance to display your knowledge on jQuery. Also to prevent any sloppy writing.
I have a radio based switch box, the markup looks like this, the id's and on/off values are generated by the values in my array with PHP...
<span class="toggle-bg">//This color is the background of the toggle, I need jQuery to change this color based on the state on/off
<input type="radio" value="on" id="_moon_page_header_area1" name="_moon_page_header_area">//this is my on value generated by the array
<input type="hidden" value="_moon_page_header_area" class="switch-id-value">// I create this input because I have multiple checkboxes that have the ID _moon_ARRAYVALUE_area1
<input type="radio" value="off" id="_moon_page_header_area2" name="_moon_page_header_area">// off value
<input type="hidden" value="_moon_page_header_area" class="switch-id-value">//_moon_ARRAYVALUE_area2
<span class="switch"></span>// the switch button that changes
</span>
Hope that makes sense and the comments are clear
Here is the jQuery
var value = $('.toggle-bg input.switch-id-value').val()
var moon1 = $('#'+value+'1').is(':checked');
var moon2 = $('#'+value+'2').is(':checked');
var static_slide = $('._moon_staticarea_height');
var toggle = $('.toggle-bg');
if(moon1){
toggle.css({'background-color': '#46b692'});
static_slide.hide()
} else
if (moon2){
toggle.css({'background-color': '#333'});
static_slide.show()
}
$('.toggle-bg').change(function () {
var value = $('.toggle-bg input.switch-id-value').val()
var moon1 = $('#'+value+'1').is(':checked');
var moon2 = $('#'+value+'2').is(':checked');
var static_slide = $('._moon_staticarea_height');
var toggle = $('.toggle-bg');
if(moon1){
toggle.css({'background-color': '#46b692'});
static_slide.slideUp()
} else
if (moon2){
toggle.css({'background-color': '#333'});
static_slide.slideDown()
}
});
it looks longer than it really is, its just repeating it self, one is on load so that it gives the correct color on load of the page, and then inside the change function we need to change colors..
How do I write it so I only have to use variables one time (so its cleaner) is there a better way to optimize it... Just NOW thinking after writing this I could put it in one function .on('load', 'change', function() {}
I just now thought of that, but I wrote all this so I am going to see what others think...
You'd do that by having the function in the change event handler, and on the end you chain on a trigger('change') to make it work on pageload :
$('.toggle-bg').on('change', function () {
var value = $('.toggle-bg input.switch-id-value').val(),
moon1 = $('#' + value + '1').is(':checked'),
slider = $('._moon_staticarea_height'),
toggle = $('.toggle-bg');
toggle.css('background-color', (moon1 ? '#46b692' : '#333'));
slider[moon1?'slideUp':'slideDown']();
}).trigger('change');
As radiobuttons can't be unchecked, it's either moon1 or moon2, which means checking one of them should be enough.
.on('change','load',
supposed to be
// Remove the comma separator if you want to bind the same handler to
// multiple events.
.on('change load',
And you can remove the one separately written out and enclose it in a function (if multiple instances of the class toggle-bg)
or just trigger the change event.(If there is a single instance of a class)
This will just run the same functionality when the page loads.
var toggle = $('.toggle-bg');
toggle.change(function () {
var value = $('input.switch-id-value', this).val(),
moon1 = $('#' + value + '1').is(':checked'),
moon2 = $('#' + value + '2').is(':checked'),
static_slide = $('._moon_staticarea_height');
if (moon1) {
toggle.css({
'background-color': '#46b692'
});
static_slide.slideUp()
} else if (moon2) {
toggle.css({
'background-color': '#333'
});
static_slide.slideDown()
}
}).change();
I am trying to create a single textbox form on a webpage to boolean test the input submitted by the user. The input will be the website user's zip code. I want to make a predetermined array of zip codes that will test true.
If it is true (the zip code entered is included in the predetermined array), I want to display one bit of HTML, and if it tests false, I want to display another bit.
I've searched around and looked in some of my JavaScript books (I've just started learning) and haven't found an answer; could someone help me out with this? Thanks!
HTML:
<label id="input-label" class="invalid">
ZIP code: <input id="zipcode" />
<div class="valid-message">
Valid
</div>
<div class="invalid-message">
Invalid
</div>
</label>
CSS:
#input-label.valid .valid-message { display: block; }
#input-label.valid .invalid-message { display: none; }
#input-label.invalid .valid-message { display: none; }
#input-label.invalid .invalid-message { display: block; }
Javascript
function isValidZip(z) {
return ['12345','67890'].indexOf(z) != -1;
}
var label = document.getElementById('input-label');
var input = document.getElementById('zipcode');
input.onkeydown = function() {
label.className = isValidZip(input.value) ? "valid" : "invalid";
}
You could try something like this(might be a little off I'll double check then get back to you :) ):
var zipArr = ['98671','97006'];//insert the zip/post codes here
var userInputEl = document.getElementById('userInput');//Get the element could use tag names or it would be better actually if you used jQuery but yeah
var elToShow = document.getElementById('elementToShowIfNotFound');
var otherElToShow = document.getElementById('idOfOtherelementToShow');
var userInput = userInputEl.value();//might be .text()
if(zipArr.indexOf(userInput) === -1){//-1 means it isn't found in the array
zipArr.push(userInput);//pushes the new one onto the array
elToShow.style.display = 'block';//this changes the css display to block instead of it being hidden.
}else{
otherElToShow.style.display= 'block';
}
Might not be the best way to do this, but I'd suggest using jQuery it makes this process a lot easier.
I have a div that basically represents a book (so a nice div layout with an image of the book, title, price, red background if on sale etc.). So what i do is to get the properties of a book from the database, insert the values in kind of an html template and display it.
Now, once it is displayed i hate how i have to handle the data. I have to either parse css properties to figure out if a book is on sale for an example or i have to keep the data in another place as well (some javascript array or use the jquery data feature). The first option is ugly the second one would require me to update two things when one property changes - which is ugly as well.
So what i would like is to handle that block of html (that represents a single book) as an object. Where i can call obj.setPrice(30); and things like that and finally call obj.update(); so it would update its appearance.
Is there anyway to accomplish this ? Or something like this ? I just feel that once i render the data as html i loose control over it :(
Suppose your html div is like this
<div id="book1">
<div id="price">$30</div>
...
</div>
You can define a Book object as follows:
var Book = function(name) {
this.name = name;
}
Book.prototype = {
setPrice : function(price) {
this.price = price;
},
update : function() {
pricediv = document.getElementById(this.name)
pricediv.innerHTML = '$'+price;
}
}
var book = new Book('book1')
book.setPrice(50);
book.update();
I guess your best shot is write your own object / methods for that.
var Book = function(){
var price = args.price || 0,
color = args.color || 'red',
height = args.height || '200px',
width = args.width || '600px',
template = "<div style='background-color: COLOR; width=WIDTH; height: HEIGHT;'><span>$PRICE</span><br/></div>";
return {
setPrice: function(np){
price = np;
return this;
},
setColor: function(nc){
color = nc;
return this;
},
setHeight: function(nh){
height = nh;
return this;
},
render: function(){
template = template.replace(/COLOR/, color);
template = template.replace(/PRICE/, price);
// etc
// use jQuery or native javascript to form and append your html
$(template).appendTo(document.body);
}
};
};
This is just a pretty basic example which can be optimized like a lot. You may even think about using John Resigs microtemplate (http://ejohn.org/blog/javascript-micro-templating/)
Usage from the above example would look like:
var book = Book({
price: 30,
color: 'blue'
});
book.render();
To change values:
book.setPrice(140).setColor('yellow').setHeight('500').render();
I have been playing around with Microsoft's proposal for jQuery Templates and Data Linking and so far it's going awesome.
TLDR, checkout this demo.
It's extremely easy to just link up a piece of HTML with a JavaScript object and from thereon, only update the JavaScript object and the HTML updates automatically.
Here's a simple example. Create the HTML that will represent your widget.
<div class="book">
<img width="100" height="100" src="" />
<div class="title"></div>
<div class="price"></div>
</div>
Then create a JavaScript object and dynamically link it to the HTML above. Here is a sample object:
var book = {
title: "Alice in Wonderland",
price: 24.99,
onSale: true,
image: "http://bit.ly/cavCXS"
};
Now onto the actual linking part. The items we are going to link up are:
A data-onsale attribute in the outer div which will be either "true" or "false"
The image src attribute to the image property of our book
title div to the title property
price div to the price property
The following sets up the linking. Note that we are only doing a one way linking here, but it's possible to setup a two way linking also using the linkBoth function.
$(book)
.linkTo('title', '.title', 'html')
.linkTo('price', '.price', 'html')
.linkTo('image', '.book img', 'src')
.linkTo('onSale', '.book', 'data-onsale')
That's it. From now onwards, just update the book object and the HTML will automatically update. Update the properties of the book like you would update html attributes using the attr function.
$(book).attr({
price: 14.75
});
or
$(book).attr('price', 14.75);
The code above is only using Data Linking, but the proposal also mentions combining data linking with templates which would make this even more easier. From what I reckon, you would be able to do this and get the above functionality:
<script id="bookTemplate" type="text/html">
<div class="book" data-onsale="{{link onSale }}">
<img width="100" height="100" src="{{link image }}" />
<div class="title">{{link title }}</div>
<div class="price">{{link price }}</div>
</div>
</script>
Link the above template with the book object in one step and add it to the page:
$('#bookTemplate').render(book).appendTo('body')
Update the properties of the book object, and changes will reflect.