I am aware of the basics of using the HTML5 localStorage using the localStorage.getItem/setItem.
But I am trying to understand how to implement the same on my dynamic page. So here is the scenario:
I have a dynamic page (myPage.jsp) which on initial load calls a Java method (that outputs the HTML string) as below;
<div id="mainContainer">
<div id="parent1"><span>Parent 1</span></div><ul id="child1"></ul>
<div id="parent2"><span>Parent 2</span></div><ul id="child2"></ul>
<div id="parent3"><span>Parent 3</span></div><ul id="child3"></ul>
</div>
Here the number of parent div's are dyanamic based on some logic.
Now on click on any of the parent divs, a Java method is called again (that again outputs the HTML string) for the child innerHTML.
The HTML returned (on click of say Parent 2) is as follows;
<li class="listEle">Child content 1</li>
<li class="listEle">Child content 2</li>
Here the number of "li" elements are dynamic for each parent.
Actually the above HTML is just appended to the mainContainer....So the overall HTML code looks like
<div id="mainContainer">
<div id="parent1"><span>Parent 1</span></div><ul id="child1"></ul>
<div id="parent2"><span>Parent 2</span></div><ul id="child2"><li class="childLi">Child content 1</li><li class="childLi">Child content 2</li></ul>
<div id="parent3"><span>Parent 3</span></div><ul id="child3"></ul>
</div>
Now my question is I want to use localStorage for 2 things:
Storing the initial HTML code (mainContainer) without any child content; AND
Storing the child HTML code as well (which is within the mainContainer)
I am looking at the various ways in which I can do this. I am open to all ideas that you can think of. Just need to consider that all things are dynamic (number of parent divs/child li's, etc)...So need to know how I can handle that dynamic content.
You can store anything you like in localStorage provided the item stored is turned into a string, no problem in your case, and the total storage doesn't exceed 5Mb per site.
You approach could something like this.
When the page loads (use jQuery) check if the base HTML template is there
If not use jQuery to load it and store it in localStorage
use a jQuery selector to select the appropriate element in the current page. This could be the element. And use $(...).html(stored html template); to display the base html.
If you need to insert dynamic values use something like John Resig MicroTemplating to insert variables.
Related
I am wondering if there is a way to insert text, schema data in particular, into a html div tag using javascript. I know there are methods for modifying existing values inside a tag such as class, href, title, but can't seem to find a way to add something new.
Basically I have <div id="main"> and I want to modify it to be <div id="main" itemtype="http://schema.org/SomeCategory" itemscope> and to be able to remove it later.
The context for such a need is using fetch / js to replace parts of webpages rather than reloading the entire page. The product pages use the schema notation, whereas general info pages do not, though all templates use the "main" div.
Unbeknownst to me, the innerHTML function attached to the body tag allows me to change actual div tags using replace. So it is simple:
input ='<div id="main">';
output='<div id="main" itemtype="http://schema.org/SomeCategory" itemscope>';
document.body.innerHTML = document.body.innerHTML.replace(input,output);
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
I am struggling to get JQM to reinitialize a jquery page with a listview that contains form fields.
One of the form elements is initialized as part of JQM's normal initialization process, that is displaying correctly with all the correct class applied to all elements.
The others are all added dynamically using JQ's append
When elements are added dynamically I cannot find the correct method to reinitialize the list to apply the styling to everything, the fieldcontain div the label & the textarea.
I have prepared an example to show the different methods to reinitialize the elements that I've tried based on other questions found on SO and around the web.
http://jsfiddle.net/robaldred/UPsQr/
In my example, row 5 is correctly initialize, however it requires calling the fieldcontain() method the textinput() method and manually add the ui-input-label class to the label. This feels like a lot of messing about, I must be missing something.
Trigger a create event on the page like this:
$("#page").trigger("create");
Create vs. refresh: An important distinction
Note that there is an
important difference between the create event and refresh method that
some widgets have. The create event is suited for enhancing raw markup
that contains one or more widgets. The refresh method should be used
on existing (already enhanced) widgets that have been manipulated
programmatically and need the UI be updated to match.
For example, if you had a page where you dynamically appended a new
unordered list with data-role=listview attribute after page creation,
triggering create on a parent element of that list would transform it
into a listview styled widget. If more list items were then
programmatically added, calling the listview’s refresh method would
update just those new list items to the enhanced state and leave the
existing list items untouched.
Referenece: http://jquerymobile.com/demos/1.0/docs/pages/page-scripting.html
Updated your fiddle - http://jsfiddle.net/UPsQr/2/
Working Example:
http://jsfiddle.net/UPsQr/4/
JS
$('#add_element').click(function() {
var list = $('ul[data-role="listview"]');
var nextLi = ((list.children().length) + 1);
li = '<li><div data-role="fieldcontain"><label for="textarea'+nextLi+'">Input:</label><textarea id="textarea'+nextLi+'" name="textarea'+nextLi+'"></textarea></div></li>';
list.append(li);
list.listview('refresh');
$('#page').trigger('create');
});
//$('#add_element').hide();
HTML
<html>
<head>
</head>
<body>
<div id="page" data-role="page">
<!-- First field is done by jQM's normal initialization -->
<!-- The Rest are added onload and appended to the listview -->
<ul data-role="listview">
<li>
<div data-role="fieldcontain">
<label for="textarea1">Input:</label>
<textarea id="textarea1" name="textarea1"></textarea>
</div>
</li>
</ul>
<a data-role="button" id="add_element">Add Fields</a>
</div>
</body>
</html>
NOTE:
jQM Supports jQuery 1.6.4
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..
Am I better to move a node I sent down form the server or to insert it?
I'm using jQuery (1.4) but would like to know for both jQuery and JS in general. In this case the node is small with only one child. But what if it were a large list?
What
large list 1 = 200 li nodes
large list 2 = 1000 li nodes
Example:
Insertion:
<div id="wrap">
<div id="box></div>
</div>
$('#box').before($('<ul id="list"><li>...</ul>'));
vs
Manipulation:
<div id="wrap">
<div id="box></div>
</div>
<ul id="list"><li>...</ul>
$('#list').insertBefore($('#box'));
The client is going to spend a lot more time rendering your new items than it will actually putting them into the DOM. I would recommend you remove the #list from the DOM entirely, add the items to it, and then put it back into the DOM. At least for large data sets.
Even then, the repaint could be slow, especially on IE with complex CSS.
The two are the same. If you look at the source, you can see that 'insertBefore' is merely mapped to 'before'.
REF for 'insertBefore': http://gist.github.com/277432#LID4389
REF for 'before': http://gist.github.com/277432#LID4088
One way to improve performance would be to provide a context for the insertion.
When doing $('#list').insertBefore($('#box')); , you should provide the context node if you have it, rather than research the entire tree. Something similar to
var myWapper = getWrapperFromEventOrWhereEverYouMightHaveIt();
//more code doing fancy things here
$(myWrapper, '#list').insertBefore($('#box'));
If your entire list is updated when you get data from the server then you should have a structure that resembles something like this:
<div id="wrap">
<ul id="list"></ul>
<div id="box></div>
</div>
Then you can have all the nodes sent as just a list of li elements and then do something like so:
$("list")[0].innerHTML = xhr.responseText // response text is of form
//<li>item</li><li>item</li>... etc
Tests have shown that innerHTML is faster then append, insert (before and after) etc.
http://www.quirksmode.org/dom/innerhtml.html