How to Hide elements based on id in ng-repeate - angularjs

How to hide an element based on elements id, I tried to hide the element without using:
document.getElementById('lis'+divId).style.visibility = "hidden";
but this worked while using individual elements but in case if I use ng-repeat it does not hide the element.
<li ng-repeat="dashBoardAddWidgetList in dashBoardAddWidgetLists"
ng-click="addTemplate(dashBoardAddWidgetList.widget.widgetType,$index)"
id="lis{{$index}}" >{{dashBoardAddWidgetList.widget.widgetName}}</li>
controller.js
$scope.addTemplate = function(name,divId) {
//$scope.templates.push( { name: 'achPayBankProcess.html', url: '/Templates/dashboard/widgets/achPayBankProcess.html' });
$scope.templates.push( { name: name, url: '/Templates/dashboard/widgets/'+name,isSelected:1});
document.getElementById(divId).style.visibility = "hidden";
$scope.listCount--;
};

Try this simple way like as what is #priyanka said .(take my answer like a key )
$scope.items = [{isshow:false,name:"Me"},{isshow:false,name:"We"},
{isshow:false,name:"I"},{isshow:false,name:"Us"}]
//html
<div ng-repeat="item in items">
<div ng-hide="item.isshow">
{item.name}<button ng-click="ShowOrHide(this.item, $index)">show/hide</button>
</div>
</div>
//click event
$scope.ShowOrHide(context,index)
{
context.ishsow=true;
$scope.items[index]=context;
}

Use ng-hide instead:
<li ng-repeat="dashBoardAddWidgetList in dashBoardAddWidgetLists"
ng-click="addTemplate(dashBoardAddWidgetList)"
id="lis{{$index}}"
ng-hide="dashBoardAddWidgetList.hide">
{{dashBoardAddWidgetList.widget.widgetName}}
</li>
And in your controller:
$scope.addTemplate = function(widgetList, divId) {
var name = widgetList.widget.widgetType;
$scope.templates.push({
name: name,
url: '/Templates/dashboard/widgets/'+name,
isSelected: 1
});
// Set flag for hide on true
widgetList.hide = true;
$scope.listCount--;
};

Use ng-if instead of ng-hide..it will boost performance on ng-repeat because ng-hide will keep hidden element in DOM but ng-if will remove that element form DOM..so we cant modify it in browser inspect

controller.js
$scope.addTemplate = function(name,divId) {
//$scope.templates.push( { name: 'achPayBankProcess.html', url: '/Templates/dashboard/widgets/achPayBankProcess.html' });
$scope.templates.push( { name: name, url: '/Templates/dashboard/widgets/'+name,isSelected:1});
alert('lis'+divId);
document.getElementById('lis'+divId).style.visibility"hidden";
$scope.listCount--;
$scope.isselect=divId;
};
{{dashBoardAddWidgetList.widget.widgetName}}

Related

Custom directive dom not change when parent scope make changes using {{}} with # attribute

I am creating a custom directive with isolate scope using interpolation ({{}}) from parent scope, should be when parent scope is change the attribute should be updated with the new data. i have only 1 data been changed, the other is not change.
i dont need 2 way binding just 1 way binding is enough that is why i am using # as an attribute property.
my parent html
<button ng-click="testClick()">Test Click</button>
<my-directive ng-repeat="sensor in sensors track by sensor.sensor_name"
sensor-name="{{ sensor.sensor_name }}" display-name="{{sensor.display_name}}"
state-normal="{{ sensor.stateNormal }}" state-alert="{{ sensor.stateAlert }}"
state-total="{{ sensor.total }}"></my-directive>
my directive template
<div>
<span>{{ displayName }}</span>
</div>
<div>
Normal
</div>
<div>
{{ states["Normal"] }}
</div>
<div>
Alert
</div>
<div>
{{ states["Alert"] }}
</div>
<div>
Total
</div>
<div>
{{ states["Total"] }}
</div>
inside my parent scope
$scope.sensors = [{
sensor_name: "stre",
display_name: "Stre"
}];
var initState = {
normal: "0",
alert: "0"
};
var setInitState = function(sensors) {
for (let i = 0; i < sensors.length; i++) {
sensors[i]["stateNormal"] = "0";
sensors[i]["stateAlert"] = "0";
sensors[i]["total"] = "0";
}
return sensors;
}
$scope.sensors = setInitState($scope.sensors);
$scope.testClick = function() {
$scope.sensors[0].display_name = "testchange";
$scope.sensors[0].stateNormal = "15";
$scope.sensors[0].total = "38";
}
my directive scope
app.directive("myDirective", function() {
return {
restrict: 'EAC',
controller: function($scope) {
$scope.states = {
"Normal": $scope.stateNormal ? $scope.stateNormal : 'x',
"Alert": $scope.stateAlert ? $scope.stateAlert : 'x',
"Total": $scope.stateTotal ? $scope.stateTotal : 'x'
};
},
templateUrl: "my-directive.php",
scope: {
sensorName: '#',
displayName: '#',
stateNormal: '#',
stateAlert: '#',
stateTotal: '#'
}
};
});
the button click is expecting changes towards all the value, but when the button click only the display_name is change but normal and total value is not changing.
you can refer to this plunkr: https://embed.plnkr.co/aXctKP/
you can check out this working plunker.
You can check out angularjs docs here to better understand how directive work.
What I do to make it right is I rename the variable inside my-directive.php to follow the attribute you have set in the index.html. You can read the angularjs doc under the Normalization section, it says that it will normalize the element's attribute from state-total to stateTotal.

Ng-repeat - "Are you sure to delete ?" from a modal

I'm retrieving a list of objects (item) from a Django API.
my_app.factory('list_of_items', function($resource) {
return $resource(
'/api/petdata/') });
Then I display everything in a html page within a ng-repeat:
<div ng-controller="ModalDemoCtrl">
<div ng-repeat="item in items | filter:{display:'1'} | orderBy: 'item_name'">
<div class="box box-widget widget-user">
{{ item.pet_name }}{% endverbatim %}
<button type="button" class="btn btn-box-tool" ng-click="askDelete(item)" href="#"><i class="fa fa-times"></i></button>
</div>
<div>
Everything's fine so far.
Then I want the user to be able to delete one of the item by clicking on the button from the html page.
What means deleting here :
1. Update the API database by changing the property "display:1" to "display:0".
2. Remove the item from the ng-repeat.
I want to make a "Are you sure" modal to confirm the delete process.
This is the askDelete function.
angular.module('djangular-demo').controller('Ctrl_List_Of_Pets', function($scope, $http, $window,$filter,list_of_pets,pet_by_id,$uibModal) {
$scope.items = list_of_items.query()
$scope.askDelete = function (idx,item,size,parentSelector) {
// console.log("PET",$scope.pet_to_be_undisplayed);
var parentElem = parentSelector ?
angular.element($document[0].querySelector('.modal-demo ' + parentSelector)) : undefined;
var modalInstance = $uibModal.open({
animation: true,
ariaLabelledBy: 'LOL',
ariaDescribedBy: 'modal-body',
templateUrl: "myModalContent.html",
controller: function($scope) {
$scope.ok = function() {
modalInstance.close();
};
$scope.cancel = function() {
modalInstance.dismiss('cancel');
};
},
size: size,
appendTo: parentElem,
resolve: {
}
});
modalInstance.result.then(function() {
reallyDelete(item);
});
};
var reallyDelete = function(item) {
$scope.entry = items_by_id.get({ id: item.id }, function() {
// $scope.entry is fetched from server and is an instance of Entry
$scope.entry.display = 0;
$scope.entry.$update({id: $scope.entry.id},function() {
//updated in the backend
});
});
$scope.items = window._.remove($scope.items, function(elem) {
return elem != item;
});
};
});
What works :
Updating the DB works with a PUT request (code hasn't been provided).
What doesn't work :
Removing the item from the ng-repeat never works. Or it throws me an error like here because it doesn't know window._.remove or it doesn't know $scope.items. It depends from what I try. Or the modal close and there is no update of the ng-repeat list, no refresh and every items remain whereas the PUT request to update worked.
I read every article on scope inheritance and I think I didn't make any mistake here but I'm might be wrong. I've been struggling for too long so I post here !
Would you suggest anything to make it work ?
Thank you for your rime.
First:
$scope.askDelete = function (idx,item,size,parentSelector) receives the item index, the item, size, and parent selector... and you are calling ng-click="askDelete(item)"
I assume you are attempting to pass the item, but in askDelete you are receiving as first parameter the index (maybe you should do ng-click="askDelete($index)"?)
Second:
In reallyDelete why are you removing the items array like this:
$scope.items = window._.remove($scope.items, function(elem) {
return elem != item;
});
?
IMHO, it would be a much cleaner code if we just do:
$scope.items.splice(idx, 1) //<- idx would be the idx of the entry in the items
You may want to take a look at Splice

angular js ng-class shows expression as class instead of processing it

I'm trying to make highlighted menu items by using angular js. I've read this question and tried implementing the anwser, but instead of angular evaluating the expression, it just shows it as the class name. I don't know what's going on.
I have the menu items listed as JSON, and the iterate trough it with ng-repeat. Once the list items are created, I want the angular to add a class of 'active', if the location url is the same as the link.href attribute of a menu item (it's a json attribute, not the html one).
Here's the relevant html:
<div class="header" ng-controller="NavbarController">
<ul>
<li ng-repeat="link in menu" ng-class="{ active: isActive({{ link.href }}) }"><a ng-href="{{ link.href }}">{{ link.item }}</a>
</li>
</ul>
</div>
and my controller:
.controller('NavbarController', function ($scope, $location) {
// navbar links
$scope.menu = [
{
item: 'PTC-Testers',
href: '#/PTC-Testers'
},
{
item: 'articles',
href: '#/articles'
},
{
item: 'PTC sites',
href: '#/sites'
},
{
item: 'account reviews',
href: '#/account_reviews'
},
{
item: 'forum',
href: '#/forum'
},
{
item: 'contact us',
href: '#/contact'
},
{
item: 'login',
href: '#/login'
}
]; // end $scope.menu
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
});
This is the navbar part of a bigger project, and I tried only inserting the relevant code. If you need further info to understand the question properly, please let me know.
It should be ng-class="{'active' : isActive(link.href)}"
You didn't end the curly brace in ng-class and its better to put class name inside quotes

Angular model doesn't scope to variable within child DOM element?

I have this markup:
<div data-ng-model="currentUser.attributes">
<div>{{username}}</div>
</div>
And this is a stripped down version of my controller:
$scope.username = "Alice";
$scope.currentUser = {
attributes: {
username: "Bob"
}
};
I want Bob to display, but instead, I am getting Alice. It works just fine if I use this:
{{currentUser.attributes.username}}
But I don't want to have to scope down to this variable's properties every time I want to access something. How can I get the element to exist within the scope of currentUser.attributes?
While I don't think you should really do this, it is what you're asking for. You can essentially mimic with by using ng-repeat on an array that you populate with the relevant object. For example:
<div ng-repeat="user in [currentUser.attributes]">
{{ user.username }}
</div>
Working plunker: http://plnkr.co/edit/svwYEeWMQXjuAnLkr9Vz?p=preview
Other possible solutions would be to have a service or controller that has functions to get the attributes and return them, cleaning up the syntax of your HTML and making it easier to change backend stuff without breaking your frontend. Your choice.
Edit: I noticed you actually expect to be able to do {{ username }} and get the relevant info, if that's really what you want then I suggest my second proposal. Create functions that return the relevant info.
<div>
{{ getCurrentUserName() }}
</div>
$scope.getCurrentUserName = function() {
return $scope.currentUser.attributes.username;
};
Your call, take it or leave it.
If you want Bob just do the the following in your HTML.
<div>{{current user}}</div>//IGNORE THIS
<div>{{currentUser.attributes.username}}</div>//UPDATED CORRECTED
UPDATED based on clarification.
So in Knockout you do this
<p data-bind="with: currentUser.attributes">
<div data-bind="text: userName></div>
<div data-bind="text: login></div>
<div data-bind="text: bhalBlah></div>
<div data-bind="text: yaddaYadda></div>
</p>
<script type="text/javascript">
ko.applyBindings({
currentUser: {
attributes: {
userName : 'Bob',
login : 't#e',
blahBlah : 'ttttt',
yaddaYadda: 'x'
}
}
});
</script>
Same thing in AngularJS would be
<p ng-controller="myCtrl">
<div>{{currentUser.attributes.userName}}</div>
<div>{{currentUser.attributes.login}}</div>
<div>{{currentUser.attributes.blahBlah}}</div>
<div>{{currentUser.attributes.yaddaYadda}}</div>
</p>
<script type="text/javascript">
angular.module('myApp',[]).controller('myCtrl',function($scope){
$scope = {
currentUser: {
attributes: {
userName : 'Bob',
login : 't#e',
blahBlah : 'ttttt',
yaddaYadda: 'x'
}
};
});
</script>
In this the question is how to avoid how not to repeat the part the full property paths between ** as shown below in angular.
**currentUser.attributes.**userName
**currentUser.attributes.**login
**currentUser.attributes.**blahBlah
**currentUser.attributes.**yaddaYadda
Here is one way see plnkr using ng-init which reduces 'currentUser.attributes' to just 'attr'.
With just attr.<properties> repeated
{{attr.userName}}
{{attr.login}}
{{attr.blahBlah}}
{{attr.yaddaYadda}}
Another way is you restructure your object and flatten it on the $scope.
This is not recommended because now you are putting primitives on to the $scope and are widening the scope with $scope.userName = currentUser.attributes.username. Also your 'repetitive' code is still there just in the Javascript.
In lieu of ng-init
ng-init="attr = currentUser.attributes"
You could also do this in controller
$scope.attr = currentUser.attributes;
This post really got me thinking. I had a theory on how to accomplish this using a directive.
Came up with a proof of concept on plnkr: http://embed.plnkr.co/OJDhpJ1maEdSoPvlbiRA/
If I understand correctly, you want to only display the properties within a given block of your struct.
Given the following struct:
$scope.currentUser = {
attributes: {
username: 'Batman',
age: '99',
address: {
street: 'Bat Cave'
}
}
};
You want to scope things down with something like:
<div scope-with="currentUser.attributes">
Username: {{username}}<br />
Age: {{age}}
<div scope-with="address">
Street: {{street}}
</div>
</div>
Directive:
angular.module('mymodule', [])
.directive('scopeWith', function($interpolate){
return {
restrict: 'A',
scope: {
scopeWith: '='
},
transclude: 'element',
compile: function(tElement, tAttrs, linker) {
return function( scope, element, attr) {
var childScope,
parent = element.parent(),
withBlock = null
;
scope.$watch('scopeWith', function(val){
childScope = scope.$new();
angular.forEach(val, function(val, prop){
childScope[prop] = val;
});
if(withBlock) {
withBlock.el.remove();
withBlock.scope.$destroy();
}
linker(childScope, function(clone){
withBlock = {};
parent.append(clone);
withBlock.el = clone;
withBlock.scope = childScope;
});
}, true);
};
}
};
Use {{currentUser.username}} to show Bob.
The ng-model on the div is irrelevant as it only applies to input elements.

AngularJS - Is there an easy way to set a variable on "sibling" scopes?

I have this problem where I am trying to make a click on a div hide all the other divs of the same "kind". Basically I'd have to, from a child scope set the variable on all other "sibling" scopes.
To illustrate this, I have created the following:
HTML
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div ng-repeat="model in models" ng-controller="MyChildCtrl">
<a ng-click="toggleVisibility()">toggle {{ model.name }} {{ visibility }}</a>
<div ng-show="visibility">
{{ model.name }}
</div>
</div>
</div>
</div>​
JavaScript
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
console.debug('scope');
$scope.models = [
{ name: 'Felipe', age: 30 },
{ name: 'Fernanda', age: 28 },
{ name: 'Anderson', age: 18 }
];
}
function MyChildCtrl($scope) {
$scope.visibility = false;
$scope.toggleVisibility = function() {
$scope.visibility = !$scope.visibility;
}
}
JSFiddle: http://jsfiddle.net/fcoury/sxAxh/4/
I'd like that, every time I show one of the divs, that all other divs would close, except the clicked one.
Any ideas?
#kolrie while your approach works I would suggest a different solution which doesn't require any changes to the model. The basic idea is to keep a reference to a selected item and calculate viability by comparing a current item (inside ng-repeat) with a selected one.
Using this solution the toggle function would become:
$scope.toggleVisibility = function(model) {
$scope.selected = model;
};
and calculating visibility is as simple as:
$scope.isVisible = function(model) {
return $scope.selected === model;
};
Finally the relevant part of the markup is to be modified as follows:
<div ng-controller="MyCtrl">
<div ng-repeat="model in models">
<a ng-click="toggleVisibility(model)">toggle {{ model.name }} {{ isVisible(model) }}</a>
<div ng-show="isVisible(model)">
{{ model.name }}
</div>
</div>
</div>
Here is a complete jsFiddle: http://jsfiddle.net/XfsPp/
In this solution you can keep your model untouched (important if you want to persist it back easily) and have AngularJS do all the heavy-lifting.
OK, I have added a visible attribute to the model, and I managed to get this done:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
console.debug('scope');
$scope.models = [
{ name: 'Felipe', age: 30, visible: false },
{ name: 'Fernanda', age: 28, visible: false },
{ name: 'Anderson', age: 18, visible: false }
];
}
function MyChildCtrl($scope) {
$scope.toggleVisibility = function() {
angular.forEach($scope.models, function(model) {
model.visible = false;
});
$scope.model.visible = true;
}
}
Live here: http://jsfiddle.net/fcoury/sxAxh/5/
Is this the most efficient way? Do you think it's a good practice if I inject this visible attribute into my model data after getting it via AJAX?

Resources