Injecting HTML5 data attributes vs. Injecting javascript data structure - javascript

I am curious as to which of the following is better practice (and why):
Injecting data as HTML 5 data attributes:
<div class="someDiv" data-for-popup="someData"></div>
Injecting a <script> into the file with some data structure
<script>
var myMap = new Map();
myMap.set('someKey','someValue');
</script>
In both cases, I would be using javascript/jQuery to look up the value, but which is the better solution?
A little background: I am creating a static page (no communication back and forth with the server besides servicing the page) so I can't use AJAX or any other server communication to service the data. The data being injected is used for a popup that is displayed on the page when "more information" is requested for a certain page object. In other words, I need the data to be present somewhere on the page, and I'm looking for the best avenue to do so, and I am also curious why that would be the best option.

Which one is better will depend on the use you want to give to that value, and on how the value is related to a particular element. So there's not a generic answer to your question, as it would go in a case-by-case basis. A good rule of thumb would be what some people commented:
If the data is useful and specific to that element, use data-*.
If there's no connection between the data and an element, use a variable in <script>.
But there's a misconception in your question, and you are missing (imho) a really important use case: data-* attributes are not exclusive for JavaScript, they can be seen and used in CSS (as part of a selector or to be used as a value), while variables inside a <script> tag are hidden to the CSS and cannot be used.
Right now data-* attributes are mainly supported in the content property for ::before and ::after but, at least in theory, they will be allowed in other properties making them more useful for styling purposes. For example:
div[data-columns] {
column-count: attr(data-columns);
}
That rule will save you having multiple rules in your CSS, it will simplify your code and make it more robust and easier to maintain... sadly, it is not supported yet.

Store in the DOM element only what is specific for it, such as text and/or title for the popup window.
In this way your JS function can rely on the element to construct the popup.
<button data-content="My popup content" data-title="My title">More information</button>
<button data-content="My 2nd content" data-title="My 2nd title">More information</button>
$("document").on("click", "button", function () {
var $this = $(this),
title = $this.data("title"),
content = $this.data("content");
//open your popup
//$this.popup({ title: title, content: content });
})

As others have said, you should only store short, specific information about the element with a data-*.
If you are looking to display a 'more info' style popup, containing lots of information. I would store that information in a hidden div that is referenced by the element. Then use JS to show that element.
<button type="button" data-target="#product-1-more-info">Product 1</button>
<button type="button" data-target="#product-2-more-info">Product 2</button>
<div id="product-1-more-info" style="display:none;">
More awesome info about product #1
</div>
<div id="product-2-more-info" style="display:none;">
More awesome infor about product #2
</div>
<script>
$('button').click(function() {
$($this.data('target')).show();
});
</script>
Of course this can be dressed up with animations and light box effects. But now you aren't storing giant amounts of data in the element and your JS is much simpler.

Related

Reload DIV from javascript

I'm not an experience programmer in JavaScript and I'm struggling with reloading data in a specified DIV.
I have an example here. The original code is more complex I contains a calendar with disabled days. After the update new disabled days are calculated and should be listed in the calendar. However this example shows the issue. When clicking the button the text "Updated text" should appear instead of "Original text".
Any suggestions?
var bla = "Original text";
function js_updtest() {
bla = "Updated text";
$("#test").load(" #test");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="inlay">
<div id="middle">
<div id='test'>
<script type="text/javascript">
document.write(bla)
</script>
</div>
<input type='button' value='Update' name='Updatetext' onclick='js_updtest();'>
</div>
</div>
There are a couple of fundamental problems here, and your best bet is probably to start over on some introductory JavaScript tutorials. But specifically the two problems are:
Here you set a new value to a variable:
bla = "Updated text";
But you don't re-use that variable anywhere. It was used once, with its initial value, when the page loaded. Updating the value of a variable doesn't update all of the places where it has already been used.
After updating it, use it. For example:
document.getElementById('test').innerText = bla;
(Note that this would also be a better way to initially use the variable on page load. document.write() is pretty much universally frowned upon. Don't think of it in terms of writing to the document, think of it in terms of identifying the DOM element to update and updating it.)
What are you even trying to do here?:
$("#test").load(" #test");
The jQuery .load() function is for making an AJAX request to fetch new content from the server and directly write it to a target element. But that doesn't appear to be what you want to do here at all. It looks like this statement (and jQuery in general) can just be removed.

Make function run after page loads and edit Label's innerHTML without ID or a Class

I am trying to design my teachable-based website, and I can only edit the following relevant fields:
HTML/JavaScript code snippets inside the head tag on all pages.
custom CSS across all pages on your site.
I have jQuery.
While this is pretty limiting I manage to get by. However, I ran into a problem:
I am trying to edit the text of this object:
a picture of the object I am trying to edit.
Basically, I am trying to edit the inner HTML of both
<label for="subject">Subject</label>
<label for="student_message">Message</label>
From "Subject" to "נושא" and from "Message" to "הודעה".
These labels have no classes and ID's, and their only attributes are "for" attributes.
Now, if it helps, these specific labels are inside these divs:
<form id="contact-form" accept-charset="UTF-8" method="post">
<div class="row form-group">
<label for="subject">Subject</label>
<label for="student_message">Message</label>
</div>
</form>
These are the only lables on the site inside the "contact-form" div.
So, the problems are:
I need to access these labels from the HEAD tag, and they are in the
BODY tag. So I guess I need some sort of a waiting function to run
after the page/form loads.
I can only differenciate these labels from
others using their attribute and their parent div's attributes.
My questions:
How do I make a function that runs after the page loads but doesn't make the whoe page freeze?
Inside that function, How do I access objects using their attributes?
And just because it seems important and I don't know it yet, how do I access objects within objects?
Thank you very much :)
You said you had jQuery available, so enclosing your code in $(document).ready( ensures the body is loaded. Then use jQuery selector to find object by attribute:
$(document).ready(function () {
$("label[for='subject']").html('נושא');
$("label[for='student_message']").html('הודעה');
});
The elements of interest can be found relative to element(s) that can be found directly - ie elements identified by id/class.
For example ...
jQuery(function($) {
const $formGroup = $('#contact-form div.form-group').eq(0);
$formGroup.find('label').eq(0).text('נושא');
$formGroup.find('label').eq(1).text('הודעה');
});
Alternatively, if you prefer not to make an assignment ...
jQuery(function($) {
$('#contact-form div.form-group').eq(0)
.find('label').eq(0).text('נושא')
.next('label').text('הודעה');
});

How to capture clicked element using $(this) inside of a vue(js) instance

I am reworking an old app of mine and I am having issues with dom manipulation and basic selections within a vue instance.
Essentially I have information in a database that I load in via ajax.
Each record in the db has 2 sections. The header tab(title, time, date etc) and the body of the record(notes, ideas, etc)
When loaded, the header shows normally to the user but if they want to see what that note contains, they have to click on the header for the bottom to appear.
consider the following html:
<vuejs for loop>
<div v-bind:id='item._id' class="tabW" v-on:click="blueTabClick" >
<div class="blueTabMainColor">
<!-- header stuff here -->
</div>
<div class="notesOpenedW">
<!-- interior informaton here, HIDDEN BY CSS -->
</div>
</div>
<vuejs for loop ender>
This HTML is essentially inside a Vue for/loop directive, and generates however many "tabs(tabW)" as needed based on how much info I have in the DB
All I want the user to do is to be able to click whichever tab(tabW) they want information on, and for the notes show underneath(notesOpenedW).
I stripped my entire app and js and tried to keep it as simple a test as possible and even with the below, I still can't get anything.
here is my JS(JQ):
$(document).ready(function(evt){
$(".blueTabMainColor").click(function(){
$(this).next(".notesOpenedW").fadeToggle();
});
});
With this basic code, when I put it inside a Vue instance, via:
methods: {
blueTabClick: function (evt) {
evt.preventDefault();
$(".blueTabMainColor").click(function(){
//alert("you clicked me");
$(this).next(".notesOpenedW").fadeToggle();
});
}
}
It doesn't work, but if I take it out of the Vue instance, it works just fine.
how can I get this to work? or am I going about it the wrong way?
Vue will not cohabit happily with JQuery. You're $(this) will not work because you're not even in the document at that point, you're in pure js, virtual DOM, another universe. Then, if it did, the event listener you call may not exist. You will need to fundamentally transition this code to Vue if you want it to work, I fear.
You can achieve this by setting a ref on "notesOpenedW".
https://v2.vuejs.org/v2/api/#ref
I would strongly recommend to wrap this behaviour in a dedicated component
That would have the following content :
<div class="tabW" v-on:click="blueTabClick" >
<div class="blueTabMainColor">
<!-- header stuff here -->
</div>
<div class="notesOpenedW" ref="notesToggleDiv">
<!-- interior informaton here, HIDDEN BY CSS -->
</div>
</div>
And the method :
methods: {
blueTabClick: function () {
$(this.$refs.notesToggleDiv).fadeToggle();
}
}
Be aware that when using Vue, manipulating directly the dom is usually a bad idea.
As i showed you, it is possible to use jQuery with Vue if you absolutely need it (or cannot afford to rework more deeply your application).
Edit : Just found this article that i think would help you a lot :
https://www.smashingmagazine.com/2018/02/jquery-vue-javascript/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=Vue.js%20Developers

Pass a PHP variable from a loop via an onclick

This may have been answered elsewhere but I couldn't find a question which fit my circumstances.
I have a site page which out puts in DIVs records from a database, this the same DIV looped. In this DIV I have a button which brings up a modal box. This modal DIV however is not coded within the looped DIV.
I need the modal box to be able to get the ID of the record for the data which the looped DIV is showing.
The button is:
<a href = "javascript:void(0)"onclick = "document.getElementById('light2').style.display='block';document.getElementById('fade').style.display='block'">
<div class= "obutton feature2">Reserve Book</div>
</a>
I assume I'll need to use java script somehow, but I don't know how to use it in this manner.
Ideally using some sort of form $_POST would be easiest with the form button having the set value of the $row->ID, but I can't make a form button also a can I?
Sorry for the possibly silly question, as I've said I've found similar things asked, but always find it hard to understand the full workings on other peoples scenarios as opposed to my own.
All help appreciated -Tom
I think the key to your answer is understanding how JS (and jQuery) uses this. When a function is called, the caller is almost always passed as the this variable. For example:
<button data-id="1234" onclick="runThisFunction()" value="run" />
<script>
function runThisFunction() {
//Do Stuff
var data_id = this.data('id');
};
</script>
In the above code, this contains the button that was clicked on. You can get lots of information from the this variable. In jQuery, you can even get to siblings, parents, or children in the DOM.
Here is an example solution to your question:
http://jsfiddle.net/yr6ds/1/
Here is a more elegant solution:
http://jsfiddle.net/yr6ds/2/

Html Helpers generates ID from model properties. How do I target 1 particular element with JavaScript and CSS if many elements have the same ID?

As it's recommended, Javascript must be kept in a physically separate file (to be unobtrusive). So how do I access a particular element in particular page? should I detect those elements by id? that would mean 2 elements can't have the same id even if they are not located in the same page.
Well, for instance, using the Html helpers methods generates element's name + id from the model's properties. If I use the same model in several pages, many elements will have the same id. How can I target them in different pages. By the way, CSS work the same way.
EDIT
Let's say I've this
<% = Html.TextBoxFor(x => x.FirstName)%>
It will generates
<input type = "Text" name = "FirstName" id = "FirstName"/>
Let's say I've this textbox in 2 differen pages. If want, for instance, to disable the textbox located in page A, how do I do it knowing they are two of them in 2 different pages. How do I discriminate them from my external javascript file?
Thanks for helping
I suggest that for each page the uses the same model, you create a wrapper div
<div class="pageA">
// the model stuff here
<% = Html.TextBoxFor(x => x.FirstName)%>
</div>
<div class="pageB">
// the model stuff here
<% = Html.TextBoxFor(x => x.FirstName)%>
</div>
and then use Jquery selectors to get the correct element $(".pageA input[name='FirstName']") (not sure if this syntax is correct).
You cannot have multiple elements on the page with the same id. That isn't valid HTML.
So when you use the same HTML helper multiple times, you need to pass different names:
<%: Html.TextBox("Foo", Model.Foo) %>
<%: Html.TextBox("Bar", Model.Bar) %>
Correct me if i'm wrong, but are you saying, you have some elements with the same id, on multiple pages, that you want to attach different behaviour to? If so then this could help you out. if not, then what Craig said.
You can use more specific selectors, or give your selectors context
have a look at the documentations here: http://api.jquery.com/jQuery/
under this header:
jQuery( selector, [ context ] )
it explains a bit about selects and context. you should be able to use this and some creative page building to target the right element with your jQuery.
So you have two files, each with a text field with the id "FirstName". When you're script runs on Page A you want to disable the field, but not when your script runs on Page B.
Is the structure of the two pages identical? I suspect not if you're handling these fields differently. Use the context to your advantage. Like if the one on Page A is in a div with id "thisDiv" and the other is in a div with id "thatDiv" you could document.getElementById('thisDiv'). If you get an element then disable the field, if not do nothing.
If you want a more specific answer you're going to have to give us more context.
Well JavaScript may be kept in a separate file or not, but it is definitely included as part of the HTML send to the browser for a particular page. I Hope I've understood your question, but, generally if you have you JavaScript code in a file, lets say utils.js then in your html generated should include (probably within the <head> tag):
<script type="text/javascript" src="/path/to/utils.js"></script>
The script get included in the page, and when the browser encounters this, it loads and then runs the script, for that page. Therefore, it is not important what the ids for elements on different pages are.
Does that make sense, or have I completely misunderstood your question?
Update:
Ok, so based on your comments, I think I understand. You have
//Page 1
//When loaded, this input should flash blue via javascript for example
<input id="firstName" .../>
And
//Page 2
//When loaded, this input has some other fancy effect/behaviour
<input id="firstName" .../>
Well in this case, as far as I see, there are only 2 types of answers. Have two seperate external js files, one per page and this way you can change to your hearts content ...OR... have some sort of hidden field in your page that tells your script what page it is looking at (this seems hacky)
<input type="hidden" value="page1"/> //etc..

Categories