Angular js : Dynamic expression not working for ng-switch [duplicate] - javascript

I have a div based on switch but the switch has a boolean variable but the value will be evaluated based on the row.id. Can some one tell me what I am doing wrong here ?
<div ng-switch="hasUrl">
<a ng-switch-when="row.id.indexOf(':') < 0 === true" href="{{url + row.id}}"> <!-- hasUrl = true -->
{{getName(row)}}
</a>
<a ng-switch-default href=".......">
{{getName(row)}}
</a>
</div>

You don't need the ===, remove it.
<div ng-switch="hasUrl">
<a ng-switch-when="row.id.indexOf(':') < 0" href="{{url + row.id}}"> <!-- hasUrl = true -->
{{getName(row)}}
</a>
<a ng-switch-default href=".......">
{{getName(row)}}
</a>

Be aware that the attribute values to match against cannot be
expressions. They are interpreted as literal string values to match
against. For example, ng-switch-when="someVal" will match against the
string "someVal" not against the value of the expression
$scope.someVal.
So according to the docs take following example to solve your case:
<div ng-switch="hasUrl">
<span ng-switch-when="row.id.indexOf(':') < 0"> WONT SHOW </span> <!-- WILL NOT WORK EVER -->
<span ng-switch-when="makeItWork"> ALSO, WONT SHOW</span>
<span ng-switch-when="true">WILL NOT SHOW EITHER</span>
<span ng-switch-when="1">WILL SHOW</span>
</div>
Look carefullyat scope variables and their values:
$scope.hasUrl = 1; /* NOTICE != true BUT 1*/
$scope.row = {};
$scope.row.id = "true:";
$scope.makeItWork = $scope.row.id.indexOf(':') > 0 ? 1 : 0;
console.log($scope.makeItWork); /* SEE THAT TRUE WILL BE LOGGED BUT IT STILL WONT SHOW */
So even though ng-switch will evaluate an expression, it seems ng-switch-when wont. If I were you I would just stick to ng-if instead.
FIDDLE Fixed fiddle

Related

How to remember current toggle state in this example after page refresh with local storage?

I have 3 tabs: 'Monday', 'Tuesday' and 'Favorites'. Each tab contains boxes with an empty heart at start ('.favorite i'). I want to save the current toggle class after refresh.
Toggle:
heartLink.find('i').toggleClass('fa-heart-o fa-heart'); // .selected or not
I've started with:
if (heartLink.find('i').hasClass('fa-heart-o')) {
localStorage.setItem('displayIcon', 0);
} else {
localStorage.setItem('displayIcon', 1);
}
And then I know I will need something similar to this but don't know how to do it..
To make clear: I want to save the current state of each specific heart. I don't one icon to affect all boxes.
var showIconToggle = localStorage.getItem('displayIcon');
if (showIconToggle == 'true') {
// some code
}
HTML:
<section id="speakers-programme">
<div class="container">
<div class="tabs_main">
<div class="col-md-5"><a data-target="#mon" class="btn active" data-toggle="tab">Monday</a></div>
<div class="col-md-5"><a data-target="#tue" class="btn active" data-toggle="tab">Tuesday</a></div>
<div class="col-md-2"><a data-target="#fav" class="btn active" data-toggle="tab"><i class="fa fa-heart" aria-hidden="true"></i></a></div>
</div>
<div class="tab-content">
<div class="tab-pane active" id="mon">
<br>
<div class="spaces">
<div class="box-container">
<div class="box not-selected" id="box1">
<i class="fa fa-heart-o" aria-hidden="true"></i>
</div>
</div>
<div class="box-container">
<div class="box not-selected" id="box2">
<i class="fa fa-heart-o" aria-hidden="true"></i>
</div>
</div>
</div>
</div>
<div class="tab-pane active" id="tue">
<br>
<div class="spaces">
</div>
</div>
<div class="tab-pane active" id="fav">
<br>
<div class="spaces">
</div>
</div>
</div>
</div>
</section>
JS:
$('div.tab-pane').on('click', '.favorite', function(e) {
e.preventDefault();
var heartLink = $(this);
//TOGGLE FONT AWESOME ON CLICK
heartLink.find('i').toggleClass('fa-heart-o fa-heart'); // .selected or not, you need those 2 classes to toggle.
if (heartLink.find('i').hasClass('fa-heart-o')) {
localStorage.setItem('displayIcon', 0);
} else {
localStorage.setItem('displayIcon', 1);
}
});
var showIconToggle = localStorage.getItem('displayIcon');
if (showIconToggle == 'true') {
// some code here
}
Fiddle: https://fiddle.jshell.net/itsfranhere/1q93a6x1/9/
This is a question folowing up that one.
To save your not cloned element states (favorited or not), add this:
At the end of the click handler, save the classes for the clicked i.
// save this current toggle state
localStorage.setItem(box.attr("id"), $(this).find("i").attr("class"));
console.log($(this).find("i").attr("class"));
On page load, before loading the favorites from localStorage, apply those saved classes:
// Load heart's element states
$(".box").each(function(){
console.log( $(this).attr("id") );
console.log( localStorage.getItem($(this).attr("id")) );
if(localStorage.getItem($(this).attr("id")) != null){
$(this).find("i").removeClass().addClass( localStorage.getItem($(this).attr("id")) );
}
});
CodePen v5
As you've seen, you need to store each heart individually.
Here's how I'd do it: in the HTML, give each heart an id. When a heart is clicked, save the new state in localstorage under favorite:id where id is replaced with the heart's id.
When the page loads, grab every heart on the page, and look up its favorite status using its id.
Example: https://fiddle.jshell.net/1q93a6x1/10/
If you want to use just one variable you can use a bitmask.
Theory
If you want to save 5 states, the binary value has 5 digits. In decimal it's a variable between 0 and 31.
First the easy part: How can I read out a state?
Let's say the actual state is 31 (11111) and we want to know the value of the third digit. How can we do this? Just bitwise and the state with a bitmask where all digits are zero except the digit we want to know:
11111 & 00100 = 00100
If the result is greater than zero, this digit is set.
To create the bitmask just shift a 1 by the amount of digits you want to take a look: 1 << 2 = 00100
Now the "though" part: Setting and unsetting a bit
To set a bit you have to bitwise or the bitmask:
00000 | 00100 = 00100
If this bit is already set... no problem it will be set afterwards.
If you want to unset a bit it's a bit tricky: You can xor the bitmask, but if the bit wasn't set before it's now set.
00100 ^ 00100 = 00000, BUT
00000 ^ 00100 = 00100 (now it's set. It's a trigger, not an unset)
The way you can be sure is: create the inverted bitmask and use bitwise and:
00100 & (00100 ^ (11111)) = 00100 & 11011 = 00000, AND
00000 & (00100 ^ (11111)) = 00000 & 11011 = 00000
Now let's code
For this you take the position of the heart in the dom and use it as an exponent to the base of 2. If you want to set a heart, add this value, if you want to remove it subtract it (Or in bitwise operations: | (or) for adding and & (and) for removing).
saving the actual state:
var $heartLinks = $('.favorite');
var $heartLink = $(this);
var position = $heartLinks.index($heartLink); // this is the position inside the bitmask
var actualBitmask = parseInt(localStorage.displayIcon || '0', 10);
var bit = (1 << position);
var invertedBit = bit ^ ((1 << $heartLinks.length) - 1);
if(!$heartLink.find('i').hasClass('fa-heart-o'))
actualBitmask |= bit;
else
actualBitmask &= invertedBit;
localStorage.setItem('displayIcon', actualBitmask);
and calling it when site is ready:
var showIconToggle = localStorage.displayIcon || 0;
$heartLinks.map(function(idx) {
if((showIconToggle & Math.pow(2,idx)) > 0)
$(this).find('i').toggleClass('fa-heart-o fa-heart');
});
working fiddle

Angularjs ng-show on ng-click not working

I have created a button like with angularjs,
<button class="btn btn-setting" ng-click="showSearch = ! showSearch" >
<img src="theme/images/settings.png" width="111">
</button>
And a div like ,
<div ng-include="'pages/include/search.html'" ng-show="showSearch" ></div>
I need to toggle the visibility of the above div on the button click.but it is not showing.
Update the showSearch model as follows
$scope.showSearch = {hideShowSearch : false}
Updated HTML
<button class="btn btn-setting" ng-click="showSearch.hideShowSearch = ! showSearch.hideShowSearch" >
<img src="theme/images/settings.png" width="111">
</button>
<div ng-show="showSearch.hideShowSearch" >This is the test</div>
EDIT -
In your script hideShowSearch is primitive one.So it does not perform two way data-binding.As result you not getting expected result.
Just do
<button ng-click="setshowme(show)"></button>
$scope.setshowme = function (value) {
if(value == true){
$scope.show = false;
}else{
$scope.show = true
}
}
Here is a simple JSFiddle
<button class="btn btn-setting" ng-init="showSearch = true" ng-click="showSearch = (showSearch) ? false : true;" >
<img src="theme/images/settings.png" width="111" />
</button>
<div ng-show="showSearch">Hello World</div>
First check these two elements (<button> & <div>) inside two ng-controllers
If so this will not work since ng-controllers have their own scopes. So that showSearch is in one scope and other controller scope do not have direct access to it.
Then check something like,
<div ng-show='showSearch'>show / hide div ...</div>
and see if this div is toggling its visibility.
if it working properly
then check the path to src of ng-include is correct.
here is a DEMO

jQuery Replicate an existing Div Multiple Times

I am building a search query which gives me results.
I have a template ready for the item inside a hidden div. What I want to do is replicate the template n number of times using jQuery.
So For example:
I search for flights and I get 5 search results, I need to replicate the below div template 5 Times
<div id="oneWayFlightElement" class="displayNone">
<div id="flightIndex1" class="flightDetailElement boxShadowTheme">
<div id="flightDetailsLeftPanel1" class="flightDetailsLeftPanel marginBottom10">
<div class="fullWidth marginTop10">
<span id="flightPriceLabel1" class="headerFontStyle fullWidth boldFont">Rs 9500.00</span><hr/>
<div id="homeToDestination1" class="flightBlockStyle">
<span id="flightNumberFromHome1" class="fontSize16">AI-202</span><br/>
<span id="flightRouteFromHome1" class="fontSize26">PNQ > DEL</span><br/>
<span id="flightDepartTimeFromHome1" class="fontSize26">Depart: 10.00 AM</span><br/>
<span id="flightArrivalTimeFromHome1" class="fontSize26">Arrive: 12.00 PM</span><br/>
</div>
<div id="destinationToHome1" class="flightBlockStyle">
<span id="flightNumberToHome1" class="fontSize16">AI-202</span><br/>
<span id="flightRouteToHome1" class="fontSize26">PNQ > DEL</span><br/>
<span id="flightDepartTimeToHome1" class="fontSize26">Depart: 10.00 AM</span><br/>
<span id="flightArrivalTimeToHome1" class="fontSize26">Arrive: 12.00 PM</span><br/>
</div>
</div>
</div>
<div id="flightDetailsRightPanel1" class="flightDetailsRightPanel textAlignRight marginBottom10">
<img src="images/flightIcon.png" class="marginRight10 marginTop10 width40"/><br/>
<button class="marginRight10 marginBottom10 width40 bookNowButtonStyle">Book Now</button>
</div>
</div>
</div>
Inside this div for 5 times
<div id="searchFlightResultDiv" class="fullWidth" style="border:solid">
</div>
Is there a better way to do that rather than string appending in jQuery?
Thanks,
Ankit Tanna
You'll need to wrap your template div (#flightIndex1) in a container with a unique id attribute. Then, you take the contents of that container (a template for a single record), and append it to your results div (#searchFlightResultDiv) using some type of loop based on the number of results received.
Basically,
HTML:
<!-- Here's your template -->
<div class="displayNone" id="oneWayFlightElement">
<!-- This id (singleResult) is important -->
<div id="singleResult">Result</div>
</div>
<!-- Container for the results -->
<div id="results"></div>
Javascript:
//Get the number of results.
//This can be sent from your API or however you're getting the data.
//For example, in PHP you would set this to $query->num_rows();
var count = 5;
//Start a for loop to clone the template element (div#singleResult) into div#results 'count' times.
//This will repeat until the number of records (count) has been reached.
for (i = 1; i <= count; i++) {
//Append the HTML from div#thingToRepeat into the #results.
$('#results').append($('#singleResult').clone());
}
Here's a JSFiddle to show you how it works. You can play with it and tweak it if necessary.
I can't in good conscious complete this post without telling you the downsides of this. Doing it this way is majorly frowned upon in the web development community and is super inefficient. It may be good for practice and learning, but please do take a look at and consider a javascript templating framework like moustache or handlebars. It does this same thing but way more efficiently.
Hope this was helpful!
function populateResult(resCount) {
resCount = typeof resCount === 'number' ? resCount : 0;
var res = [];
var templateEle = $('#oneWayFlightElement');
for(var i = 0; i < resCount; ++i)
res.push(templateEle.clone().removeAttr('id class')[0]);
$('#searchFlightResultDiv').html(res);
}
populateResult(5);
We use an array res to hold the DOM elements as we loop and finally sets it to the target div using html method. We don't need a JQuery object here as the html method accepts any array like object. In this way we can minimize browser reflows. Here is the JSFiddle

ng-switch is not matching with the expected option

I'm having problems with angularjs ng-switch
JS
function TestCtrl($scope) {
$scope.currentUser = {"userId":"1","userRole":"N"};
$scope.userRoles = {"normal":"N","admin":"A"}
$scope.patient = {name: 'John'};
}
HTML
<div ng-switch on="currentUser.userRole">
<a ng-switch-when="userRoles.normal" href="normalUrl">
{{patient.name}}
</a>
<a ng-switch-when="userRoles.admin" href="adminUrl">
{{patient.name}}
</a>
<div ng-switch-default> default </div>
</div>
</div>
I expect the name of the patient to be displayed with a link to normalUrl but 'default' is displayed. What am I doing wrong?
Here is a fiddle with the code
The ngSwitchWhen directive does not evaluate expressions (although I've heard this might be added to 1.3). The value is interpolated as a string literal, so you would have to use it like this:
<a ng-switch-when="N" href="normalUrl">
That will work, but if you really need to dynamically determine your when value, then maybe ngIf will better suit your needs:
<a ng-if="currentUser.userRole === userRoles.normal" href="normalUrl">
<a ng-if="currentUser.userRole === userRoles.admin" href="adminUrl">

Using razor to build a popup tooltip menu

I am having a problem with dynamically generating this dropdown menu. This works if I'm not making it dynamically.
The #t.Id is working and is different every time in the loop. I'm pretty sure its the first line that's wrong as I have used the id="" before this way.
<b>tagged</b>
<div style="display: none;">
<div id="tagsdiv#(t.Id)">
<span class="menu">hhhh<br />
nnnn
#for( int i = 0; i < t.tTags.Count; i++ ) {
<b>#Html.ActionLink( t.tTags[i], "TagDetail", "Forums", new { tag = t.tTags[i], page = 0 }, null )</b>
}
</span>
</div>
</div>
Tips to debug Razor (or any server-side code rendering markup) more effectively:
View the rendered HTML! is it correct?
Remove styles/scripts until you are sure the server is rendering the values you want.
Add a breakpoint to your controller to make sure you are passing data to the view. Your rendering logic may be fine.
That said, your code appears to work fine. I dummied up some data:
#{ var t = new { Id = 1234, tTags = new List<string> { "foo", "bar", "baz" } }; }
<b>tagged</b>
<div style="display: none;">
<div id="tagsdiv#(t.Id)">
<span class="menu">
#for( int i = 0; i < t.tTags.Count; i++ ) {
<b>#Html.ActionLink( t.tTags[i], "TagDetail", "Forums", new { tag = t.tTags[i], page = 0 }, null )</b>
}
</span>
</div>
</div>
This yields:
<b>tagged</b>
<div style="display:none;">
<div id="tagsdiv1234">
<span class="menu">
<b>foo</b>
<b>bar</b>
<b>baz</b>
</span>
</div>
</div>
One thing that really looks wrong here is '#tagsdiv1234'. Are you sure your tooltip needs an ID including the CSS/jQuery ID selector ("#")?
Another thing that stands out is your tooltip container is wrapped with an outer div set to display:none. The ID'd element will always be hidden because its parent is hidden, even if the tooltip code tries to show it.
Another possibility is that your ID contains a character illegal in an element identifier.

Categories