How to use $event only for parent element in Angular JS? - angularjs

I have HTML code with ng-click event:
<div class="btn share" ng-click="do($event)">
<span">1</span>
</div>
Angular JS:
$scope.do = function (event) {
var target = angular.element(event.target);
var parsed = parseInt(target.find('span').text(), 10);
}
When I click to element div or child element span is called event do().
But if I click on span my counter inside span is not increment. Only by clicking parent element div.
How I can set same $event for div and span elements?

I would recommend to work with scope bindings instead of DOM textContent:
<div class="btn share" ng-click="do()">
<span>{{count}}</span>
</div>
and in controller
$scope.count = 0;
$scope.do = function () {
$scope.count++;
};
If you however still want to know why it failed with your approach, it's because you need to use currentTarget, not just target:
angular.module('demo', []).controller('MainCtrl', function($scope) {
$scope.do = function(event) {
var target = angular.element(event.currentTarget);
var parsed = parseInt(target.find('span').text(), 10);
target.find('span').text(parsed + 1);
};
});
<script src="https://code.angularjs.org/1.4.3/angular.js"></script>
<div ng-app="demo" ng-controller="MainCtrl" class="btn share" ng-click="do($event)">
<span>1</span>
</div>
But don't do this, controller should not work with DOM at all, this is
not what controllers are for.

You're doing it the wrong way. Angular is not jQuery. You shouldn't do any DOM manipulation in the controller. The view should be generated based on the model, and not vice-versa.
The code should be
<div class="btn share" ng-click="do()">
<span>{{ counter }}</span>
</div>
and in the controller:
$scope.counter = 1;
$scope.do = function() {
doSomethingWithCounter($scope.counter);
}

Have you tried adding the same click event to your span also?
Like this
<span ng-click="do($event)"> 1 </span>

Related

Allow only one collapse div in ng-repeat

I have some data in the ng repeat, and inside that I have some data under each divs which is collapsed.
No when I click on the main div, I want only one div to collapse in at a time.
Eg: if I click abc, asdasd should be displayed.. Then if I click abc1, asdasd1 should be displayed but NOT asdasd
<script>
angular.module('myApp', [])
.controller("Ctrl_List", ["$scope", function(s) {
s.people = [
{name:"Sten", age:"49"}
,{name:"John", age:"39"}
,{name:"Hanne", age:"37"}
,{name:"Jens", age:"37"}
,{name:"Brian", age:"24"}
,{name:"Johnny", age:"24"}
,{name:"Peter", age:"49"}
]
s.obj = [
{
"name":'abc',
"text":'asdasd'
},
{
"name":'abc1',
"text":'asdasd1'
}
]
}])
html:
<body ng-app="myApp" ng-controller="Ctrl_List">
<div ng-repeat="ob in obj">
<button class="btn" data-toggle="collapse" href="#abc-{{ob.name}}"> {{ob.name}}</button>
<div id="abc-{{ob.name}}" class="collapse">{{ob.text}}</div>
</div>
</body>
data-parent is not working for me, or may be I am not using it properly.
Please Check the Fiddle here
Using a pure Angular approach rather than using JQuery for this.
Add a new property show to the each object and use ng-if to show/hide its corresponding text using a method in controller.
<div ng-repeat="ob in obj">
<button class="btn" ng-click=" showThis(ob)"> {{ob.name}}</button>
<div ng-if="ob.show">{{ob.text}}</div>
</div>
controller method
s.showThis = function(obj) {
//Hides all
angular.forEach(s.obj, function(ob) {
if(ob.name != obj.name) {
ob.show = false;
}
});
//Toggles current object show/hide
obj.show = !obj.show;
}
Working Fiddle

Dynamic controller change in angularjs

I need to dynamically change controller of one particular div by clicking some input buttons.
Why it works the first way, but doesn't work the second way if I replace one-element array by controller itself (see code below).
And how to implement such functionality in a better way?
Plnkr with one-element array (works)
index.html
<body ng-app="myApp">
<div ng-controller="MyCtrl">
Hello, {{name}}!
<input type="button" value="click me" ng-click="changeCtrl(0)"/>
<input type="button" value="click me" ng-click="changeCtrl(1)"/>
<input type="button" value="click me" ng-click="changeCtrl(2)"/>
<div ng-repeat = "ctrl in curCtrl" ng-controller="ctrl">
{{ blah }}
</div>
</div>
</body>
</html>
script.js
var myApp = angular.module('myApp', []);
myApp.controller("MyCtrl", MyCtrl);
function MyCtrl($scope) {
$scope.name = 'Username';
$scope.ctrls = [ctrlA, ctrlB, ctrlC];
$scope.curCtrl = [ctrlA];
$scope.changeCtrl = function (idx) {
$scope.curCtrl = [$scope.ctrls[idx]];
}
}
function ctrlA($scope) {$scope.blah = "One";}
function ctrlB($scope) {$scope.blah = "Two";}
function ctrlC($scope) {$scope.blah = "Three";}
Plnkr with controller instead (doesn't work)
index.html
<body ng-app="myApp">
<div ng-controller="MyCtrl">
Hello, {{name}}!
<input type="button" value="click me" ng-click="changeCtrl(0)"/>
<input type="button" value="click me" ng-click="changeCtrl(1)"/>
<input type="button" value="click me" ng-click="changeCtrl(2)"/>
<div ng-controller="curCtrl">
{{ blah }}
</div>
</div>
</body>
</html>
script.js
var myApp = angular.module('myApp', []);
myApp.controller("MyCtrl", MyCtrl);
function MyCtrl($scope) {
$scope.name = 'Username';
$scope.ctrls = [ctrlA, ctrlB, ctrlC];
$scope.curCtrl = ctrlA;
$scope.changeCtrl = function(idx) {
$scope.curCtrl = $scope.ctrls[idx];
}
}
function ctrlA($scope) {$scope.blah = "One";}
function ctrlB($scope) {$scope.blah = "Two";}
function ctrlC($scope) {$scope.blah = "Three";}
It works with ng-repeat because ng-repeat destroys and re-compiles the HTML when the array reference changes. You would have to compile manually if you want the same result without an array, using the $compile service on the $element. It could be done in your controller, but a directive might be better.
You may also want to take advantage of client-side routing to accomplish this (ui-router allows nested states).
Check out these answers:
Dynamic NG-Controller Name
Dynamically assign ng-controller on runtime
Otherwise, you could use a quick hack with ng-if and $timeout:
$scope.changeCtrl = function(idx) {
// ng-if sees null and destroys the HTML
$scope.curCtrl = null;
$timeout(function() {
// ng-if sees a new object and re-compiles the HTML
$scope.curCtrl = $scope.ctrls[idx];
});
}
<div ng-if="curCtrl" ng-controller="curCtrl">
{{ blah }}
</div>

ng-show not working for dynamically added HTML within my controller

Please see relevant JSFiddle
Within this code I dynamically added in sanitized HTML code using ng-bind-html but when assigning ng-show to the html it does not work. I tried using $compile but so far nothing as well.
I am trying to hide and show an element using ng-show but both are visible.
JS:
var app = angular.module('App', ['ngSanitize'])
app.controller('MyCtrl', function($scope, $compile) {
$scope.myHTML = [];
$scope.myHTML.push('<li ng-show = "visible(1)">Test1</li>');
$scope.myHTML.push('<li ng-show = "visible(0)>Test2</li>');
$scope.visible = function(arg)
{
if (arg == 1) return true;
if (arg == 0) return false;
}
$compile($scope.myHTML)($scope);
});
HTML:
<div ng-app="App">
<div ng-controller="MyCtrl">
<ul ng-repeat="snippet in myHTML" ng-bind-html="snippet"></ul>
</div>
</div>
Your controller should pretty much never be aware of markup, ever. That's the power of MVC. You should repeat across a real dataset and build up markup in your view. Something like the following, where you set items = [item1, item2] in a controller.
<div ng-app="HelloApp">
<div ng-controller="MyCtrl">
<ul ng-repeat="item in items">
<li ng-show = "test($index)">Test{{$index}}</li>
</ul>
</div>
</div>
If you really need to do it the way you're doing, you should use a custom directive and use angular.element to append your compiled html to the current directive element. ng-bind-html doesn't expect a compiled node, rather just an html string.
Your method is not true.
First , your ng-repeat is in ul, scope.myHTML will loop ul instead of adding DOM in ul, so you should ng-repeat in li. code like this:
<ul>
<li ng-repeat="snippet in myHTML" ng-bind-html="snippet" ng-show="snippet.visible">{{ snippet.content }}</li>
</ul>
app.controller('MyCtrl', function($scope, $compile) {
$scope.myHTML = [{content:'Test1', visible:1},{content:'Test2', visible:0}];
$scope.visible = function(arg)
{
if (arg == 1) return true;
if (arg == 0) return false;
}
});
Maybe, you want to just add DOM like jQuery. code like this:
<ul>
</ul>
app.controller('MyCtrl', function($scope, $compile) {
$scope.visible = function(arg)
{
if (arg == 1) return true;
if (arg == 0) return false;
}
$('ul').html($compile('<li ng-show="visible(1)">Test1</li><li ng-show="visible(0)">Test2</li>')($scope));
});
i used $timeout function it's working with me : sample code
$scope.allowDelete = false;
$scope.allowDeleteCount = '';
$timeout(function () {
$('div').append($compile('<button type="button" ng-show="allowDelete" class="btn btn-danger btn-sm btn-delete"><i class="fa fa-trash-o"></i> Delete <span>{{allowDeleteCount}}<span></button>')($scope))
},1000);

angularjs scope variable change onclick for conditional div

i have two divs i want to show them conditionally with onclick event .
my-angular-app.js
$(document).on('click', '#showless', function(el) {
var appElement = document.querySelector('[ng-app=myapp]');
var $scope = angular.element(appElement).scope();
$scope.$apply(function() {
$scope.value = false;
});
});
$(document).on('click', '#showmore', function(el) {
var appElement = document.querySelector('[ng-app=myapp]');
var $scope = angular.element(appElement).scope();
$scope.$apply(function() {
$scope.value = true;
});
});
and my div of myapp (myapp.html)
<div ng-show="desc" id="description" class="text-muted" style="padding-top:5px;padding-left:10px;padding-right:10px;color:#2E2E2E;font-size:11px;">{{myapp.value|truncate}}<span><a id="showmore" href="">more</a></span>
</div>
<div ng-show="!desc" id="description" class="text-muted" style="padding-top:5px;padding-left:10px;padding-right:10px;color:#2E2E2E;font-size:11px;">{{myapp.value}}<span><a id="showless" href="">less</a></span>
</div>
(truncate is a filter i wrote which works fine .)
I'm not exactly sure what you are trying to do, but Angular provides ng-click, so you should not have to bind to $(document).on('click').
I'd suggest a simpler approach for conditional show:
<div ng-show="desc" id="description" class="text-muted" style="padding-top:5px;padding-left:10px;padding-right:10px;color:#2E2E2E;font-size:11px;">{{myapp.value|truncate}}<span><a id="showmore" ng-click="desc = true" href="#">more</a></span>
</div>
<div ng-show="!desc" id="description" class="text-muted" style="padding-top:5px;padding-left:10px;padding-right:10px;color:#2E2E2E;font-size:11px;">{{myapp.value}}<span><a id="showless" ng-click="desc = false" href="#">less</a></span>
</div>
The above uses ng-click to set the value of desc. Therefore, you don't need any other logic in the controller to toggle the divs.

AngularJS on-off switch

I want a button in angularJs, that when I press it a function is called and when I press it again it does another function, like an ON-OFF switch.
I have this:
<a ng-click="addForm(data)" href=""> <div class="starOff" ng-class="{starOn: checkF(data)}"></div> </a>
I would to call another function when I click it once.
You can use ng-switch.
<div ng-app ng-controller="Ctrl">
<div ng-switch on="selected">
<button ng-switch-when='true' ng-click='button1()'>button1</button>
<button ng-switch-when='false' ng-click='button2()'>button2</button>
</div>
</div>
function Ctrl($scope) {
$scope.selected = true;
$scope.button1 = function () {
//do logic for button 1
$scope.selected = !$scope.selected;
console.log('btn1 clicked');
}
$scope.button2 = function () {
//do logic for button 2
$scope.selected = !$scope.selected;
console.log('btn2 clicked');
}
}
Demo on jsFiddle
Why don't you change the ng-click to something other than addForm(data), like handleClick(data), and then in your controller you can define handleClick(data) to call addForm(data) if a certain flag is already true?
Another possible solution, using ng-click and ng-class to toggle the class.
HTML
<div ng-app="miniapp">
<div ng-controller="Ctrl">
<a ng-click="newClass=toggleClass($event)" ng-class="newClass" href="">Toggle</a>
</div>
</div>
JS
var $scope;
var app = angular.module('miniapp', []);
function Ctrl($scope) {
$scope.toggleClass = function(obj) {
if (obj.srcElement.className == 'starOn') {
return 'starOff';
} else if (obj.srcElement.className == 'starOff') {
return 'starOn';
} else {
return 'starOn';
}
}
};
There are probably better ways to grab the current class name.
Here's the full jsFiddle.
Try using a property instead of a call to the function checkF(). Pretend the property is mySwitch. When your addForm() is called, set mySwitch to true.
How To Toggle A Function Using ng-click
One (of many) methods to swap between two functions when using ng-click. It uses a similar method to what tnunamak suggested.
HTML
<div ng-app="miniapp">
<div ng-controller="Ctrl">
<a ng-click="toggle(toggled)" ng-init="toggled=false" href="">Toggle</a>
</div>
</div>
JS
var $scope;
var app = angular.module('miniapp', []);
function Ctrl($scope) {
$scope.toggle = function(toggled) {
if (toggled == false) {
alert('Function A');
$scope.toggled = true;
} else if (toggled == true) {
alert('Function B');
$scope.toggled = false;
}
}
};
And the full jsFiddle.
You can implement it using Font-Awesome and angular js with following example
<div class="onoffswitch" >
<input type="checkbox" name="someOnOFF" class="onoffswitch-checkbox" id="myonoffswitch6" ng-model="vm.youmodelOnOff" />
<label class="onoffswitch-label" for="myonoffswitch6">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>

Resources