Angular ng-show/ng-hide issue in nested ng-repeat - javascript

I'm new to angular and I know this question has already been asked so many times but I'm not able to make it here.
Here is the JSBin for my problem:
What I'm trying to accomplish here a list of cards (trello style) but I'm not able to make it as it does in trello. Here when clicking add card, angular's compile successfully add the card to list but I'm stuck to hide add card anchor tag then. I've applied some ng-show/ng-hide but then it doesn't maintain the index and hides other add card anchor in the ng-repeat (I know its natural but I'm not able to sort it out). Can somebody please help me here. Thanks
Here is the code as well:
Angular code:
angular.module('app', []).controller('DemoCtrl',function($scope,$compile,$window){
$scope.items = [];
$scope.idx = '';
$scope.c = {};
$scope.addNewList = function () {
if(typeof $scope.c.newList === 'undefined'){
alert('list title blank');
return;
}
$scope.items.push({listTitle: $scope.c.newList});
$scope.c.newList = '';
};
$scope.addNewCardToList = function(idx) {
$scope.idx = idx;
var elm = '<div class="list-card"><textarea style="overflow: hidden; word-wrap: break-word; resize: none; height: 56px;" ng-model="c.title"></textarea><input type="button" value="Add" ng-click="saveNewCardToList(idx)">X</div>';
var temp = $compile(elm)($scope);
if($window.document.getElementsByClassName("list-card").length === 0)
angular.element(document.querySelector('#compose_'+idx)).append(temp);
};
});
HTML:
<div ng-controller="DemoCtrl">
<div ng-repeat="item in items" style="display:inline-block;width:120px;">
<div>{{item.listTitle}}</div>
<div ng-repeat="inner in item.items">{{inner}}</div>
<div id="compose_{{$index}}"></div>
Add a card...
</div>
<br />
Add a list...
<div ng-show="showInput">
<input type="text" placeholder="Add a list..." name="title" ng-model="c.newList">
Save
</div>
</div>

Even if your JSBin is working partially (Add and X button below textarea are not working), best solution with keeping your approach way about angular
is here
BUT, this approach doesn't seems like angular-way. Commonly, anything related with DOM controlling in controller is not best practice. This will be great guide for you.
Anyway, I completed another JSBin just working fine entirely. Take a look.

Related

How to hide an element in if statement?

I am making an html change to a CMS that will affect all pages when the changes are live. I would like this html alert to only affect 1 specific page. I am attempting to do an if statement for the page title.
The logic is that if the page title is Test Article Two then show the html that I have put in place, if not then display=none. With this logic in place, I am viewing the html on all pages not just the one I want it to show.
<div class="container">
<div class="title-wrapper">
<span id="article-banner-country">#countryFullText</span> /
<span id="article-banner-category">#subCatText</span>
<div id="article-banner-title">#pageTitle</div>
<!--page alert -->
<div class="feedback-container content-desktop" id="alert-dialog">
<div class="feedback-left">
<p>Have any feedback? Reach out to us!</p>
</div>
<div class="feedback-right">
<button class="feedback-button">Give Feedback</button>
<button class="feedback-button">Dismiss</button>
</div>
</div>
</div>
</div>
<script>
function showAlert() {
if(#pageTitle === "Test Article Two") {
document.getElementById('alert-dialog').style.display = 'block';
}else {
document.getElementById('alert-dialog').style.display = 'none';
}
}
</script>
I'd recommend changing a class on the body element so that you can use CSS for the styling.
HTML: nothing really changed here
<body>
<div class="container">
<div class="title-wrapper">
<span id="article-banner-country">#countryFullText</span> /
<span id="article-banner-category">#subCatText</span>
<div id="article-banner-title">#pageTitle</div>
<div class="feedback-container content-desktop" id="alert-dialog">
<div class="feedback-left">
<p>Have any feedback? Reach out to us!</p>
</div>
<div class="feedback-right">
<button class="feedback-button">Give Feedback</button>
<button class="feedback-button">Dismiss</button>
</div>
</div>
</div>
</div>
</div>
</body>
javascript: just check the document.title and add the class the the body element
<script>
if(document.title === "Test Article Two") {
document.body.classList.add("show-alert");
}
</script>
Use CSS for the styling. Always hide #alert-dialog and only show it when we add the class to the body.
<style>
#alert-dialog {
display: none;
}
.show-alert #alert-dialog {
display: block;
}
</style>
If you are making static pages or using server side rendering, you could add logic to add a class to show or hide the alert element without adding more javascript to the page. It will have the relevant class(es) when the html is generated and delivered. This way you won't have to create a function, call it and manipulate the DOM after everything is rendered.
I may have missed this in the code above, are you calling the showAlert function anywhere? If not, your alert won't be shown (or will be shown depending on the default styles).
One thing I'd caution against is the imperative nature of the code here. If you wanted to reuse this alert functionality on another page, you'd have to add another more logic to detect another page title every time you wanted to use the alert. Since you are using a CMS, you might consider adding a flag to show the alert, and on this specific page, turn that flag on.
If you wanted to use the function strategy, I'd set your default alert styles:
#alert-dialog {
display: none;
}
.show {
display: block;
}
and try something like this:
<script>
function showAlert() {
if(document.title === "Test Article Two") {
document.getElementById('alert-dialog').classList.add('show');
}
}
document.addEventListener("DOMContentLoaded", showAlert);
</script>
Another alternative is to take a look at the path of the page this is supposed to be on (window.location.pathname) and using regex to see if it matches what you want. I'd recommend that over looking at the title since it's more likely the title of the page will change rather than the url.
In JavaScript, you can access the page title with document.title. You should change the script like this:
function showAlert() {
if(document.title === "Test Article Two") {
document.getElementById('alert-dialog').style.display = 'block';
} else {
document.getElementById('alert-dialog').style.display = 'none';
}
}

How to remove the dynamically ng-hide class in AngularJS?

I have to implement the image upload functionality and the problem
<div class="container responsiveImageSet">
<div ng-show="imageLoader" style="text-align: center;">
<img class="imageLoaderGif" src="images/googleLoader.gif">
</div>
<div class="container" >
<span ng-repeat="imgURL in backgroundImageURL track by $index">
<img class="uploadedImageSet" src="{{imgURL}}">
</span>
</div>
</div>
is that i have show the spinner before the image is uploaded and i am using ng-show for it but in the element section dynamically class="ng-hide" is added i have to remove this class becasue class is creating a problem for me please tell me how to fix this problem?
$scope.backgroundImageURL = [];
$scope.imageLoader = false;
$scope.uploadBackgroundImage = function(event) {
$scope.imageLoader = true;
//Get the value from the input field and assign into the fireabse node
var userProductImg = $("#imgId")[0].files[0];
var PSR = firebase.storage().ref('user/image');
//get the date as well as put the imageURL from node
var rn = new Date().getTime().toString();
var task = PSR.child(rn).put(userProductImg).then(function(snapshot) {
$timeout(function(){
$scope.backgroundImageURL.push(snapshot.downloadURL);
$scope.imageLoader = false;
localStorage.setItem('userImageURL', $scope.backgroundImageURL);
}, 0);
})
}
I would certainly choose a ng-if over ng-show here.
ng-show:
The element is shown or hidden by removing or adding the .ng-hide CSS
class onto the element. The .ng-hide CSS class is predefined in
AngularJS and sets the display style to none (using an !important
flag).
ng-if :
The ngIf directive removes or recreates a portion of the DOM tree
based on an {expression}. If the expression assigned to ngIf evaluates
to a false value then the element is removed from the DOM, otherwise a
clone of the element is reinserted into the DOM.
Remember to actually use an expression :
<div ng-if="imageLoader == true" style="text-align: center;">
<img class="imageLoaderGif" src="images/googleLoader.gif">
</div>
You get rid of .ng-hide and have more accurate control, besides the element is inserted and removed when needed, not just shown or hidden by a ridiculous !important hack.

get the size of label text inside the div?

I am trying to get the size of label text inside the div and chech of the size is 0 hide this div
Update the text is in dnn_ctr2802_View_lblHelp class dnnHelpText
javascript
$('.dnnTooltip').dnnTooltip();
//get the size of the hiden label
var labelTextSize = $(".dnnHelpText").val().length;
console.log("labelTextSize");
if(labelTextSize == 0)
{
$('.dnnTooltip').hide()
}
html
<div class="pull-right eyeball">
<img id="img_type" src="/ideaPark/DesktopModules/ExplorationTypeSaftyAlert/img/3.png" />
<img id="img_safety_alert" class="eyeball-warning" src="/ideaPark/DesktopModules/ExplorationTypeSaftyAlert/img/exploration-warning.png" />
</div>
<div class="dnnTooltip">
<label id="dnn_ctr2802_View_label">
<a id="dnn_ctr2802_View_cmdHelp" tabindex="-1" href="javascript:__doPostBack('dnn$ctr2802$View$cmdHelp','')"><span id="lblLabel"></span></a>
</label>
<div id="dnn_ctr2802_View_pnlHelp" class="dnnFormHelpContent dnnClear" style="display:none;">
<span id="dnn_ctr2802_View_lblHelp" class="dnnHelpText"> bnmbnmbnmbnmtfgjnfvyg</span>
</div>
try this & BTW try to use jquery UI function .remove()
var labelTextSize = $('.dnnHelpText').text().length;
console.log("text:" + labelTextSize.length);
if (labelTextSize == 1) {
$('.dnnTooltip').remove();
}
Try this:
var labelTextSize = $("#lblLabel").width();
And to test, try this:
console.log(labelTextSize);
UPDATE:
As anything worked I have search for other way to achieve this. I have found this question and maybe it works for you.
Try this:
$(".dnnHelpText").bind("DOMSubtreeModified", function(){
var labelTextSize = $(this).width();
if(labelTextSize == 0)
{
$('.dnnTooltip').hide()
}
});
That snipet add an event listener when the content of the label is been changed. So then, inside the event you may have access to it's properties to do your routine.

Make First Ingredient never able to be deleted

I'm making an ingredients application where users insert ingredients
My application looks like this:
As you can see, the first ingredients span doesn't have a X at the end, because you must have at least one ingredient, but the rest of the ingredient spans do. I'm also using the Jquery Sortable Plugin so if you click near the outside of any of the ingredient spans, you can change the order of the ingredients. This works fine, except if you move the first ingredient span, then that span doesn't have an X at the end, even if you move it to the last spot.
So what I'm trying to do is make the first ingredient span always have no X at the end, even if switched order with another ingredient span. I tried this:
$('ingredientsCOUNT > span:first').hide(deleteButton);
but it didn't work? Any other suggestions? All help is greatly appreciated, and here's my code:
HTML (the php can just be ignored!)
<div class='formelementcontainer funky'>
<label for="ingredient">Ingredients</label>
<div id='ingredientsCOUNT' class='sortable'>
<span>
<input type="text" class='small' name="ingredient" id="ingredient" placeholder='QTY'/>
<select name='measurements'>
<option value='' name='' checked='checked'>--</option>
<?foreach ($measurements as $m):?>
<option value='<?=$m->id;?>'><?=$m->measurement;?></option>
<?endforeach;?>
</select>
<input type="text" name="ingredient" id="ingredient" placeholder='Ingredient'/>
</span>
</div>
<div class="clear"></div>
<div class='addSPAN tabover'>
<a class='float-right' id='btnAddIngredients' href='#'>Add Ingredient</a>
</div>
</div>
jQuery
(function($) {
$(document).ready(function () {
$('#btnAddIngredients').click(function () {
var num = $('#ingredientsCOUNT span').length;
var newNum = new Number(num + 1);
var deleteButton = $("<a class='float-right' style='margin:10px 2px;' href='#'><img src='<? echo base_url()."public/img/delete.png";?>' height='11' width='11' /></a>");
deleteButton.click(deleteThis);
$('#ingredientsCOUNT > span:first')
.clone()
.attr('name', 'ingredient' + newNum)
.append(deleteButton)
.appendTo('#ingredientsCOUNT')
.fadeIn();
$('ingredientsCOUNT > span:first').hide(deleteButton); //THIS IS MY SOLUTION THAT DIDN'T WORK
});
function deleteThis() {
var span = $(this).closest('span')
span.fadeOut('slow', function() { span.remove(); });
}
$( ".sortable" ).sortable(); //jQuery Sortable initialized
});
})(jQuery);
How about hiding it with CSS? The following assumes you added a class delete-button to your delete links:
#ingredientsCOUNT > span:first-child .delete-button { display: none; }
With that CSS, you can reorder the list, add or remove items, and the first delete button will never show.
Since :first-child is quirky in oldIE ( https://developer.mozilla.org/en-US/docs/CSS/:first-child#Internet_Explorer_notes ), it's possible to use the Sortable API like this:
$(".sortable").sortable({
update: function (event, ui) {
var rows = $("#ingredientsCOUNT").children("span");
rows.removeClass("first-child");
rows.first().addClass("first-child");
}
});
(there's probably a better way to utilize the event and/or ui parameters)
This way, you wouldn't have to determine which row to add a delete button to; you would always include a delete button in every row in your HTML. Then, when a sorting is done, the jQuery in the stop event (EDIT: update event) will hide the first row's delete button and show the rest (via classes).
Of course, you would need this CSS:
#ingredientsCOUNT > span.first-child a.delete-button {
display: none;
}
And to add a delete-button class to your delete buttons <a>
EDIT:
I changed the Sortable method from stop to update so that it only runs the code when the sorting arrangement has actually changed, after the sorting is done.

How to hide certain children(). of a parent(). div?

I want to display only div.card1 when a user clicks on a selection menu I have made
<table id="flowerTheme">
<tr>
<td>
<div class="card1">
<div class="guess"><img src="Test Pictures/QuestionMark.gif" /></div>
<div class="remember"><img src="Test Pictures/flower.gif" /></div>
</div>
</td>
<td>
<div class="card2">
<div class="guess"><img src="Test Pictures/QuestionMark.gif" /></div>
<div class="remember"><img src="Test Pictures/flower.gif" /></div>
</div>
</td>
</tr>
</table>
I have a function that toggles the class 'selected' when the user clicks on an image. The following works perfectly:
if($('.flowerThemePic').hasClass('selected') && $('.sixCardLayout').hasClass('selected')) {
$('#flowerTheme').css('display', 'inline');
However, as I stated before, I would like to have card2 to not be displayed. I have tried:
if($('.flowerThemePic').hasClass('selected') && $('.sixCardLayout').hasClass('selected')) {
$('#flowerTheme').not('.card2').css('display', 'inline')
But this does not do anything. I have also tried:
if($('.flowerThemePic').hasClass('selected') && $('.sixCardLayout').hasClass('selected')) {
$('#flowerTheme').find('div').not('.card2').css('display', 'inline')
But this hides both cards. What would be the right method of displaying card1 and not card2?
$('#flowerTheme').css('display', 'inline');
$('.card2').hide();
First of all, it looks to me that card1 and card2 should be id, not class. The difference is that IDs are supposed to be unique, while classes are supposed to be re-used. Since you're using card1 and card2 to uniquely identify those cards, they should be IDs. Furthermore, they probably need a class as well: probably class="card", so they can be referred to as a group.
Secondly, I think you should be using CSS, not jQuery for the actual hiding/showing. Consider this:
table#flowerTheme.selection-made :not(.selected) .card
{
display: none;
}
This would hide any element that has class="card" that doesn't have any parent with class="selected". Note the .selection-made on #flowerTheme -- this allows the default case to show every card, but then when someone clicks, you do $('#flowerTheme').addClass('selection-made'); and then $(this).addClass('selected'); (assuming you're using $(wherever selected goes).click() for this). It's a bit unclear from your question exactly where the selected class is being added, but I'd recommend doing it this way. It is far more easily maintained, jQuery has to do less work, and it leaves you with a very simple and easy way to expand the list of cards.
What about :
$('#flowerTheme .card2').hide();
?
You can write a javascript function to hide children...
function hideSpecificChildren(childClass){
var child = document.getElementByClass(childClass);
if(tab.style.display == "block") {
tab.style.display = "none";
}else {
tab.style.display = "block";
}
}
Try this:
$('#flowerTheme .card2').css('display','none').parent().show();
Demo
OR
$('#flowerTheme .card2').hide().parent().show();
Demo

Categories