Parsing html code with jQuery - javascript

I'm using the new material-design-lite (mdl) on my website. I'm also loading in dynamic content using mustache.js.
Now, the newly created elements need to be registered with using the upgradeElement function for mdl to know of them and apply the javascript to them. On their website they have some sample code to do this:
<div id="container"/>
<script>
var button = document.createElement('button');
var textNode = document.createTextNode('Click Me!');
button.appendChild(textNode);
button.className = 'mdl-button mdl-js-button mdl-js-ripple-effect';
componentHandler.upgradeElement(button);
document.getElementById('container').appendChild(button);
</script>
However, I am using jQuery and I'm not entirely sure how I should parse the whole template I get from mustache.js and register each component correctly. This is what I've tried:
var filledTemplate = '
<div class="mdl-card mdl-shadow--2dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">Title</h2>
</div>
<div class="mdl-card__supporting-text">
<p>A simple paragraph with below some radio buttons</p>
<p>
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="input_0">
<input type="radio" id="input_0" class="mdl-radio__button" name="options" value="radio1" />
<span class="mdl-radio__label">Radio button 1</span>
</label>
</p>
<p>
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="input_1">
<input type="radio" id="input_1" class="mdl-radio__button" name="options" value="radio2" />
<span class="mdl-radio__label">Radio button 2</span>
</label>
</p>
</div>
<div class="mdl-card__actions mdl-card--border">
<a class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect">
Send
</a>
</div>
</div>';
var html = $.parseHTML(filledTemplate);
$(html).find(".mdl-js-button").each(function(){
componentHandler.upgradeElement($(this));
});
The filledTemplate is just to give a clear idea of the stuff it can contain. I need to bind all input's, textareas, sliders, radios, checkboxes and a button. In the example above you can see a simple card-layout from mdl, with two radio boxes and a button.
I tried to get the componentHandler to upgrade the button-element first, but mdl returns element.getAttribute is not a function, so I guess I'm just giving the wrong value to .upgradeElement().
What am I doing wrong here?
Here is a codepen as an example: http://codepen.io/anon/pen/JdByGZ

Try componentHandler.upgradeElement(this, 'MaterialButton'); if you want just to update the button or componentHandler.upgradeAllRegistered(); to update all elements.
http://jsbin.com/tuluda/4/edit?js,output

I have structured my app as a general container and a set of views, loaded with jQuery and rendered with Hogan. I am invoking componentHandler.upgradeDom() after inserting templates and is seems to work fine.
I guess this might be optimized further, upgrading on a smaller granularity, but this simple minded approach works fine in my Phonegap application.
The variables tmpl and content are there to ease debugging, otherwise the code might be made more compact.
app.render = function(template, data, destination) {
$.get(template, function(html) {
var tmpl = Hogan.compile(html);
var content = tmpl.render(data);
$(destination).html(content);
componentHandler.upgradeDom();
});
};

Related

Binding lots of objects visibility in javascript. Managing the current state

I'm writing a website where the user would hit a button to start.
Depending on which button they push, a new section on the page will appear.
More buttons in this section - hit one of those buttons and one of a few sections will appear.
I have code which is starting to get really long and messy.
So I was looking for a cleaner/better way of managing what needs to be visible at any one time.
I want to avoid installing something like angular/react/knockout - because it seems like a lot of overhead for just 1 page on a large(ish) website. So ideally just naked javascript or jquery.
But i'd also like to avoid pages and pages of javascript full of $('div1').show(); $('div2').hide();
etc
And it is becoming difficult to manage them all.
I've created a fiddle so hopefully you can see what I am trying to accomplish (it's only about 1/5 complete but already looking a mess):
https://jsfiddle.net/6w4mfndf/
But basically it's looking like this at the moment:
<div name="Group1">
<input name="group1" type="radio" id="btn1" />
<span>1</span>
<input name="group1" type="radio" id="btn2" />
<span>2</span>
<div>
<div name="group2">
<div id="div_btn1" style="display:none">
<input name="group2" type="radio" id="btn1_1" />
<span>1_1</span>
<input name="group2" type="radio" id="btn1_2" />
<span>1_1</span>
</div>
</div>
<script>
$(function () {
$('#btn1').change(function() {
if ($('#btn1').is(':checked')) {
$('#div_btn1').show();
$('#div_btn1_1').hide();
}
});
</script>
I am working with MVC if there is any kind of way that can be used to help model the data out. (Unlikely I'd guess, but just throwing it out there).
Any solutions I am missing?
Why not try to have a class that is shared by all the buttons which triggers the js and a data attribute that informs the js as to which div of content to show?
Something along these lines for example:
<div class="content-block" id="content1">
Content 1
</div>
<div class="content-block" id="content2">
Content 2
</div>
<button class="content-button" data-content-block="content1" value="content 1"></button>
<button class="content-button" data-content-block="content2" value="content 2"></button>
<script>
$(function () {
$(".content-block").hide();
$(".content-button").click(function() {
$(".content-block").hide();
var contentBlock = $(this).attr("data-content-block");
$("#" + contentBlock).show();
});
});
</script>

Uncheck other checkboxs when one is checked

Ok I have been building this nutrition plugin for wordpress, trying to find a solution for this simple task that a couple of lines of js should work.... just to uncheck the other check boxes when one is checked.
I have 4 input's nested in div's as per this:
<div class="nutrition-mc-group nutrition-mc-group-activity-level">
<div class="nutrition-mc-selection-box">
<div class="nutrition-mc-checkbox-outter">
<input type="checkbox" id="squared-checkbox1">
<label class="nutrition-mc-checkbox" id="mc-sedentary-select" for="squared-checkbox1"></label>
</div>
<p class="nutrition-mc-notes nutrition-mc-notes-switch">Sedentary</p>
<p class="nutrition-mc-description">Typical desk job / Sitting most of the day</p>
</div>
<div class="nutrition-mc-selection-box">
<div class="nutrition-mc-checkbox-outter">
<input type="checkbox" id="squared-checkbox2">
<label class="nutrition-mc-checkbox" id="mc-lightly-active-select" for="squared-checkbox2"></label>
</div>
<p class="nutrition-mc-notes nutrition-mc-notes-switch">Lightly Active </p>
<p class="nutrition-mc-description">Walking around a good amount, retail jobs</p>
</div>
<div class="nutrition-mc-selection-box">
<div class="nutrition-mc-checkbox-outter">
<input type="checkbox" id="squared-checkbox3">
<label class="nutrition-mc-checkbox" id="mc-moderately-active-select" for="squared-checkbox3"></label>
</div>
<p class="nutrition-mc-notes nutrition-mc-notes-switch">Moderately Active</p>
<p class="nutrition-mc-description">Walking constantly in a fast paced environment, waiting tables</p>
</div>
<div class="nutrition-mc-selection-box">
<div class="nutrition-mc-checkbox-outter">
<input type="checkbox" id="squared-checkbox4">
<label class="nutrition-mc-checkbox" id="mc-vigorously-active-select" for="squared-checkbox4"></label>
</div>
<p class="nutrition-mc-notes nutrition-mc-notes-switch">Vigorously Active</p>
<p class="nutrition-mc-description">Very labor intensive, construction workers</p>
</div>
</div>
Now the js is a little different, I have tried to simplify it as much as possible:
this.allActive = this.mod.find( '.nutrition-mc-group-activity-level input');
_init: function(){
this.allActive.on('change', $.proxy( this._uncheckActivityBtn, this ) );
},
_uncheckActivityBtn: function(){
$(this.allActive).not(this).prop('checked', false);
},
It runs fine, but its like it is not recognizing the not(this) part argument.
if I change the .prop to true it changes the argument and all the inputs become checked when checking one. I cant figure out why it is not understanding the this part of the argument and not excluding the currently selected box.
I tried to just move everything in the one function but when doing a debug the output gave an error for the not(this) operator, saying something about it being unspecified.
We had similar requirement in our project and we turned up using radio button. Just change the styling as per your style guide.
Note: all radio button inputs must have the same name.

Hide and show content Angular

I am trying to create a form for users who have forgotten their login data. There are three radio buttons and when the user clicks on a radio button and clicks 'OK', the whole content hides and a new form is shown for the option they have chosen. Below the html:
<div id="MainContent">
<form ng-submit="">
<label><input type="radio" name="dataForgotten" id="unForgotten"/>Forgot username</label>
<label><input type="radio" name="dataForgotten" id="pwForgotten"/>Forgot password</label>
<label><input type="radio" name="dataForgotten" id="bothForgotten"/>Forgot both username and pw</label>
<input type="submit" value="OK">
<input type="submit" value="Cancel">
</form>
</div>
How can I make this happen with Angular? I have very little experience with Angular, so I'd really appreciate the help.
Thanks in advance!
There are two ways to achieve the desired effect.
Using ng-if
Using ng-show or ng-hide
The difference is in this, ng-if removes/recreates a portion of the DOM tree based on a Boolean expression i.e. true or false values.
On the other hand ng-show just hides the portion based on the value of the expression. It sets the display of that the part of the DOM to none.
For your case I would favor ng-if so that only the required part of the DOM is loaded into the app at the right time. Some have argued that by changing expressions on the web-inpsector, one could enable or disable an ng-show block.
Here is the Edited code. I have included a plunker. here is the link http://plnkr.co/edit/JB4LAgo9rqtPnPZHpwWr?p=preview
<label><input type="radio" value="unForgotten" ng-model="dataForgotten"/> Forgot username</label>
<br/>
<label><input type="radio" value="pwForgotten" ng-model="dataForgotten"/>Forgot password</label>
<br/>
<label><input type="radio" value="bothForgotten" ng-model="dataForgotten"/>Forgot both username and pw</label>
<div ng-if="dataForgotten == 'unForgotten'">
<!-- If Username Forgotten then Content goes here-->
Username Forgotten
</div>
<div ng-if="dataForgotten == 'pwForgotten'">
<!-- If Password Forgotten then Content goes here-->
Password Forgotten
</div>
<div ng-if="dataForgotten == 'bothForgotten'">
<!-- If Both Forgotten then Content goes here-->
Both Forgotten
</div>
Here is the explanation on the docs as regards ng-if
https://docs.angularjs.org/api/ng/directive/ngIf
While here is the documentation for ng-show https://docs.angularjs.org/api/ng/directive/ngShow
You can use ng-show for this. The directive evaluates a boolean condition and shows the content when true, so to hide one section and show another you just need the inverse.
<div ng-show="!completed">
First Section
</div>
<div ng-show="completed">
Second Section
</div>
On your $scope, you'll have a bool completed property (or whatever you want to call it) and you can change this in your controller when the button is clicked using ng-click.
<button ng-click="changeCompleted()">Show/Hide</button>
Controller:
$scope.changeCompleted = function(){
$scope.completed = !$scope.completed;
}
*Note you could also shorten this part by performing the assignment directly in the ng-click directive.
Here's a working jsfiddle example.
ng-show docs
Also, if you'd like to make sure a radio button is checked before allowing the button to be clicked, have a look at ng-disabled which allows you to conditionally disable/enable your button.
If you want to have it in plain javascript:
Close
function show(target) {
document.getElementById(target).style.display = 'block';
}
function hide(target) {
document.getElementById(target).style.display = 'none';
}
<div id="MainContent">
<form ng-submit="formsubmit(dataForgotten)">
<label><input type="radio" ng-model="dataForgotten" id="unForgotten"/>Forgot username</label>
<label><input type="radio" ng-model="dataForgotten" id="pwForgotten"/>Forgot password</label>
<label><input type="radio" ng-model="dataForgotten" id="bothForgotten"/>Forgot both username and pw</label>
<input type="submit" value="OK">
<input type="submit" value="Cancel">
</form>
<form name="secondForm" ng-show="submited">
</form>
</div>
//controller code
$scope.submited=false;
$scope.formsubmit = {
//form value insert code here
$scope.submited=true;
};

JQuery UI Buttonset in UpdatePanel

I have a server control which has a couple of radio buttons on it. I run a startup javascript script file which applied the JQuery UI buttonset() on them.
$(document).ready(function () {
$('#radiobuttonpanelid%').buttonset();
});
Everything works perfectly when outside of an UpdatePanel. If the server control is inside an update panel, no matter what I try, i get "Error: Object doesn't support property or method 'buttonset'". I get this message even the first time I open the page.
Update:
Rendered HTML when inside of the update panel looks like this:
<DIV>
<SPAN>
<INPUT name=ct1 id=ct1 type=radio CHECKED value=1>
<LABEL for=ct1>1</LABEL>
</SPAN>
<BR>
</DIV>
<DIV>
<SPAN>
<INPUT name=ct2 id=ct2 type=radio value=2>
<LABEL for=ct2>2</LABEL>
</SPAN>
<BR>
</DIV>
Anyone came across this issue?

Dojo/Dijit: Dynamically choosing input required attribute

I am attempting to put together a fairly complex form using dojo and dijit widgets. The form has multiple 'sections' which allow the user to attach an existing object (via select tag) or create an entirely new object inline in the form.
My inputs are rendered conditionally based radio buttons and manipulated via javascript. What I am having problems doing, is conditionally making dijit widgets required based on whether the inputs are rendered or not (which itself depends on which radio button is selected.
My html (actually jsp)
<div>
<input id="useExisting" type="radio" name="radio" checked value="useExisting" onclick="renderExistingInput()" /> <label for="useExisting">Use Existing</label>
<input id="new" type="radio" name="radio" value="new" onclick="renderNewInputs()"/> <label for="new">Create New</label>
</div>
<br>
<div id="newInputs">
<div class="row">
<label class="label" for="newName">Name </label>
<span class="formInput"><input type="text" id="newName" name="newName" required="true" dojoType="dijit.form.ValidationTextBox"/></span>
</div>
<!-- More inputs with required="true"-->
<br>
</div>
<div id="existingInput>
<div class="row">
<label class="label" for="existingSelect">Existing Object </label>
<span class="formInput">
<select name="existingSelect" id="existingSelect" dojoType="dijit.form.Select">
<!--JSTL tags for compiling list of options -->
</select>
</span>
</div>
</div>
Accompanying javascript functions:
function renderExistingInput() {
dojo.fx.wipeOut(getWipeArguments('newInputs')).play();
dojo.fx.wipeIn(getWipeArguments('existingInput')).play();
}
function renderNewInputs() {
dojo.fx.wipeOut(getWipeArguments('existingInput')).play();
dojo.fx.wipeIn(getWipeArguments('newInputs')).play();
}
function getWipeArguments(id) {
var wipeArgs = {
node : id
};
return wipeArgs;
}
The basic 'flow' of user interactions is User clicks a radio button, the correct div renders as a result of that. What I want then are inputs that are not rendered to not be considered required. I'm not entirely sure how to do this. Is it possible to manipulate that particular attribute directly via dojo? Or is there a better way to do this entirely?
Seem's like My answer was staring me right in the face. I simply needed to pull together the different parts I had come across. My final function for changed the 'required' attribute looks like:
function setWidgetRequiredAttributes(baseDomNodeId, requiredValue){
foundWidgets = dijit.findWidgets(dojo.byId(baseDomNodeId));
console.log(foundWidgets);
foundWidgets.forEach(function(widget){
widget.required=requiredValue;
});
}

Categories