Angular ngDisabled inside ngIf - javascript

I'm running into a roadblock. I have a simple piece of code:
<div ng-app>
<input type="checkbox" ng-model="element" />Hide Element
<div ng-if="!element">
<input type="text" ng-disabled="disable" />
<input type="checkbox" ng-model="disable" />Disable
</div>
</div>
This works fine, but I want the text and second checkbox split into multiple divs, both still dependent on the first checkbox, like:
<div ng-app>
<input type="checkbox" ng-model="element" />Hide Element
<div ng-if="!element">
<input type="text" ng-disabled="disable" />
</div>
<div ng-if="!element">
<input type="checkbox" ng-model="disable" />Disable
</div>
</div>
When I do this, the model does not get applied correctly and I'm unable to disable the text box by using the second checkbox. Am I misunderstanding the scope, or is this a bug?
I know with this example, I could wrap the two in an outer div, but my issue is that my structure is a table structure (yes, it's tabular data), where I don't want to hide an entire row, while keeping my markup as semantic as possible.
<table>
<tr>
<td></td> //this does not get hidden
<td></td> //this does not get hidden
<td></td> //this does not get hidden
<td></td> //THIS GETS HIDDEN
<td></td> //THIS GETS HIDDEN
</tr>
</table>
If you want to play, I set up a basic fiddle: http://jsfiddle.net/qkmv6wfh/

It is not a bug. The behavior you are seeing is because of the child scope created by ng-if. In your case the value set at the scope property disable is only available inside the child scope created by the second ng-if="!element" and disable inside the other block is in its own child scope. You can resolve it by setting it on an object reference where the object is initialized before any of these child scopes (ex ng-init="action ={}"), in this case both the child scopes refer to the same object reference action (as they get prototypically inherited) and modification on the property action.disabled gets reflected in both the places.
This can happen not just for ng-if any directive that creates a child scope like ng-repeat, ng-switch etc.
Read this well explained answer.
Try:
<div ng-app ng-init="action ={}">
<input type="checkbox" ng-model="element" />Hide Element
<div ng-if="!element">
<input type="text" ng-disabled="action.disable" />
</div>
<div ng-if="!element">
<input type="checkbox" ng-model="action.disable" />Disable
</div>
</div>
Bad Code Alert: I have used ng-init only for this demo purpose, you should not use ng-init for initializing. Always use a controller to initialize values on the scope.
Demo
angular.module('app', []).controller('Controller1', function() {
}).controller('dummy', function() {}).controller('Controller2', function($scope) {
$scope.action = {};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<p>With ng-init</p>
<div ng-init="action ={}" ng-controller="dummy">
<input type="checkbox" ng-model="element" />Hide Element
<div ng-if="!element">
<input type="text" ng-disabled="action.disable" />
</div>
<div ng-if="!element">
<input type="checkbox" ng-model="action.disable" />Disable
</div>
</div>
<p>With Controller As</p>
<div ng-controller="Controller1 as ctrl">
<input type="checkbox" ng-model="ctrl.element" />Hide Element
<div ng-if="!ctrl.element">
<input type="text" ng-disabled="ctrl.disable" />
</div>
<div ng-if="!ctrl.element">
<input type="checkbox" ng-model="ctrl.disable" />Disable
</div>
</div>
<p>With Controller and dot in the binding</p>
<div ng-controller="Controller2">
<input type="checkbox" ng-model="element" />Hide Element
<div ng-if="!element">
<input type="text" ng-disabled="action.disable" />
</div>
<div ng-if="!element">
<input type="checkbox" ng-model="action.disable" />Disable
</div>
</div>
</div>

Try with ng-show/hide instead:
<div ng-app>
<input type="checkbox" ng-model="element" />Hide Element
<div ng-hide="element">
<input type="text" ng-disabled="disable" />
</div>
<div ng-hide="element">
<input type="checkbox" ng-model="disable" />Disable
</div>
</div>

Related

How to target the last of type visible element with jquery

I need some help I have a drupal webform in which new form elements show conditionally if the previous text input has content.
What I’m trying to do is select all inputs that are currently visible and then specifically target the last one (the most recently shown).
The issue is this targets the last child within each .form-item rather than the last form item itself directly.
$(".webform").on("change", function() {
$(".form-item:visible").each(function() {
if ($(this).is(":last-of-type")) {
//Do whatever
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="webform">
<div class="form-item" style="display:block">
</div>
<div class="form-item" style="display:block">
</div>
<div class="form-item" style="display:block">
</div>
<div class="form-item" style="display:none">
</div>
</div>
You can simplify your flow by using this jQuery:last selector
$('.form-item:visible:last')
You may apply the below code on form field change or form submit, depending on your requirements.
<div class="webform">
<div class="form-item" style="display:block">
<input type="text" value="1" />
</div>
<div class="form-item" style="display:block">
<input type="text" value="2" />
</div>
<div class="form-item" style="display:block">
<input type="text" value="3" />
</div>
<div class="form-item" style="display:none">
<input type="text" value="4" />
</div>
</div>
<script>alert($(".form-item:visible:last input").val());</script>

Can I set ng-model to two values?

I have an input
<input type="text" ng-model="choice.text">
Where choice.text creates a new text property in the object choice. This allows me to send the contents of the input to different page. While this feature works, I would also like to add another feature where the content of the input is displayed and updated in real time on the page. Something to this effect.
Unfortunately, ng-model is already set to choice.text. Is there a way I can have set two values to one ng-model? It would perhaps look like this:
<input type="text" ng-model="choice.text name"></p>
<p ng-bind="name"></p>
If not, is there another way to achieve this effect?
EDIT: For those wondering, when I try <p ng-bind="choice.text"></p>it doesnt work for some reason.
EDIT 2: I simplified the code for the sake of the question. Here is the actual code for more detail:
<div class ="ask-container">
<div ng-switch="cbstate">
<div ng-switch-when="not-pressed">
<h1>Choose between... </h1> <!-- I would like to add the dynamic element here -->
</div>
<div ng-switch-when="pressed">
<h1>Hi</h1>
</div>
</div>
<form role="form" ng-submit="submitChoice()">
<div class="input" ng-repeat="choice in poll.options">
<input type="text" ng-model="choice.text" placeholder="Choice {{$index+1}}"><br>
</div>
<button class="add" type="button" ng-click="addChoice()">+</button>
<button class="create" type="submit">Create</button>
</form>
</div>
EDIT 3: Same code, but with the ng-bind:
<div class ="ask-container">
<div ng-switch="cbstate">
<div ng-switch-when="not-pressed">
<h1>Choose between... </h1>
</div>
<div ng-switch-when="pressed">
<h1>Hi</h1>
</div>
</div>
<form role="form" ng-submit="submitChoice()">
<div class="input" ng-repeat="choice in poll.options">
<input type="text" ng-model="choice.text" ng-change="temp=choice.text" placeholder="Choice {{$index+1}}"><br>
</div>
<button class="add" type="button" ng-click="addChoice()">+</button>
<button class="create" type="submit">Create</button>
</form>
<p ng-bind="temp"></p>
<p ng-bind="choice.text"></p>
</div>
Note: Somebody said that the ng-repeat may be messing with my scope. Maybe keep that in mind as you try and fix my problem.
For now, just list[0]. Eventually I will want them all to appear in a list but I can do that myself. For now I just want the first input to display in the bind.
To have the first of the list appear in the bind:
<div class="input" ng-repeat="choice in poll.options">
<input type="text" ng-model="choice.text" placeholder="Choice {{$index+1}}" />
<br>
</div>
<p ng-bind="poll.options[0].text"></p>
Each <div> in the ng-repeat has its own child scope with the choice property set to poll.options[0], poll.options[1], poll.options[2], etc. Simply use those values in the parent scope.
Is this not acceptable?
<input type="text" ng-model="choice.text"></p>
<p ng-bind="choice.text"></p>
Use ng-change to update other model
<input type="text"
ng-model="choice.text"
ng-change="temp=choice.text"/>
Now for testing, use:
<p ng-bind="temp"></p>
<p ng-bind="choice.text"></p>

Show/hide multiple Divs with checkbox without using ID's only class names

Hi I needed assistance with having the “show/hide div” below show and hide when you click on either of the checkboxes in a section. I am planning on having multiple sections and the number is unknown, so it will not be possible to use ID's. So I was looking for a generic way if a checkbox in one region is clicked the “show/hide” only shows up in that region. I know you can probably achieve this by writing individual code and assigning ID’s for each section, but is there a way to make it function like I am visioning to avoid having to constantly update of the code? Is it possible to just target the closest div or next to element to achieve this when the checkbox is checked/unchecked or call css classes?
Here is my HTML
<!--section 1 -->
section 1
<div class="showHideDiv">SHOW/HIDE THIS DIV</div>
<div class="custom-input">
<div class="checkbox">
<input class="" id="" name="" type="checkbox"><label class="" for="">E-mail</label>
<input class="" id="" name="" type="checkbox"><label class="" for="">Print</label>
</div>
</div>
section 2
<!--section 2 -->
<div class="ShowHideDiv">SHOW/HIDE THIS DIV</div>
<div class="custom-input">
<div class="checkbox">
<input class="" id="" name="" type="checkbox"><label class="" for="">E-mail</label>
<input class="" id="" name="" type="checkbox"><label class="" for="">Print</label>
</div>
</div>
section 3
<!--section 3 -->
<div class="ShowHideDiv">SHOW/HIDE THIS DIV</div>
<div class="custom-input">
<div class="checkbox">
<input class="" id="" name="" type="checkbox"><label class="" for="">E-mail</label>
<input class="" id="" name="" type="checkbox"><label class="" for="">Print</label>
</div>
</div>
section 4
<!--section 4 -->
<div class="ShowHideDiv">SHOW/HIDE THIS DIV</div>
<div class="custom-input">
<div class="checkbox">
<input class="" id="" name="" type="checkbox"><label class="" for="">E-mail</label>
<input class="" id="" name="" type="checkbox"><label class="" for="">Print</label>
</div>
</div>
Once you fix the invalid html (you need to add a closing </div> for <div class="custom-input">), you could use
$(this).closest('.custom-input').prev('.ShowHideDiv') //where $(this) is the checkbox
Refer this fiddle for an example (based on the comments) that hides the <div> if none of the checkboxes are checked, and displays the <div> if one or both the checkboxes are checked
I would do it like this:
$('.checkbox').on('click', function(){
$(this).closest('.custom-input').prev('.showHideDiv').toggle();
});
Just make sure your markup is closed properly and all your showHideDiv classes are exactly the same (i.e. right now some start with lowercase and some start with uppercase)
updated
http://jsfiddle.net/EEj29/

How can I select the next div using jQuery?

I am quite a noob when it comes to jQuery and I'm trying to select the next element using the next() selector but having a little trouble in getting it to work!
What I'm trying to do is to activate slideDown() once the user has finished making their selection on a ui slider. Here is my code:
$('.slider').slider({
stop: function(event, ui) {
$(this).nextAll('.secondq:first').slideDown('slow')
}
});
Trouble is, this doesn't work at all. It will only work if I put the 'secondq' question inside the parent div of the ui slider. Here is my HTML:
<div class="option">
<h2 align="left">How high is your ceiling from the floor?</h2>
<input type="text" align="right" name="bonus" class="value" disabled="disabled" />
<div class="slidewrap">
<div class="sliderFt slider"></div>
</div>
</div>
<!-- End Option -->
<div class="option">
<h2 align="left">How many windows do you have?</h2>
<input type="text" align="right" name="bonus" class="value" disabled="disabled" />
<div class="slidewrap">
<div class="sliderWinDoor slider"></div>
</div>
<div class="secondq" style="display:none;">
<h2>What type of material are your windows made of?</h2>
<div class="radiocont">
<label>Wood</label>
<input type="radio" class="styled" value="wood" name="windowtype" />
</div>
<div class="radiocont">
<label>Metal</label>
<input type="radio" class="styled" value="metal" name="windowtype" />
</div>
<div class="radiocont">
<label>PVC</label>
<input type="radio" class="styled" value="pvc" name="windowtype" />
</div>
</div>
</div>
nextAll only gets siblings. Based on your HTML structure, you could do:
$(this).parent().next()
To make it more independent from the structure, you could also do:
$(this).closest('.slidewrap').nextAll('.secondq:first')

Changing classes on multiple divs when selecting specific radio buttons

Hey everyone I got a javascript problem I can't seem to find a specific solution for on the web. What I want to be able to do is select one of the radio buttons and have that change the class of #home-right to either .rackmount or .shipping and add the class of .displaynone to the type of dimensions I don't want shown.
<div id="home-right" class="rackmount">
<h4 class="helvneuebcn">Case Finder</h4>
<div class="cta-options">
<input type="radio" value="Shipping and Storage" name="" checked> Shipping and Storage<br/>
<input type="radio" value="Rackmount Enclosures" name=""> Rackmount Enclosures<br/>
</div>
<div class="shipping-dimensions displaynone">
<div class="dimensions"><input type="text" class="size"><span class="helvneuemd">H x </span></div>
<div class="dimensions"><input type="text" class="size"><span class="helvneuemd">W x </span></div>
<div class="dimensions"><input type="text" class="size"><span class="helvneuemd">L</span></div>
</div>
<div class="rackmount-dimensions">
<div class="dimensions"><input type="text" class="size"><span class="helvneuemd">U Height x </span></div>
<div class="dimensions"><input type="text" class="size"><span class="helvneuemd">Rack Depth</span></div>
</div>
<div class="clear"></div>
<input type="button" value="Submit" class="findcase">
</div>
Use a onClick handler on your radio buttons to do your stuff. Example:
<input onCLick="..." type="radio" value="Shipping and Storage" name="" checked> Shipping and Storage<br/>
Also use jQuery if you ain't already - it will save you some time and its very easy to do this kind of functionality.

Categories