Currently I am trying to fetch some data using JSON and have structured it over my website using ng-repeat.
The problem is that on ng-click, on any newly created element the function invokes on each element as well. I have also tried using the this operator but it doesnt seem to work on angularjs.
I have created a dummy problem similar to mine.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<div ng-controller="MyCtrl">
<div ng-repeat="aplhabet in word">
<button style="width:50px; margin: 5px" ng-click="addDiv()">
<b>{{aplhabet}}</b>
</button>
<section ng-show="newdiv">functionInvoked</section>
</div>
</div>
<script>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope){
$scope.word = 'STRINGDEMO';
$scope.addDiv = function () {
$scope.newdiv = true;
}
}
</script>
</body>
</html>
As you might notice whenever you click on any button the function runs for each element. I need help to understand how to pass any identifier in this function so that the function is invoked only on the element clicked.
you need an object array to achieve this. simply use a for loop to convert this to an array of object.
for(key in $scope.word){
$scope.wordArr.push({
letter : $scope.word[key],
newDiv : false
})
}
use the new array as ng-repeat. to print letter use <b>{{aplhabet.letter}}</b>
<div ng-repeat="aplhabet in wordArr">
<button style="width:50px; margin: 5px" ng-click="addDiv(aplhabet)">
<b>{{aplhabet.letter}}</b>
</button>
<section ng-show="aplhabet.newdiv">functionInvoked
</section>
</div>
in the ng-click pass the whole object as a parameter and change the newDiv to true
Demo
var myApp = angular.module('myApp',[]);
function MyCtrl($scope){
$scope.word = 'STRINGDEMO';
$scope.wordArr = [];
for(key in $scope.word){
$scope.wordArr.push({
letter : $scope.word[key],
newDiv : false
})
}
$scope.addDiv = function (aplhabet) {
aplhabet.newdiv = true;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div ng-repeat="aplhabet in wordArr">
<button style="width:50px; margin: 5px" ng-click="addDiv(aplhabet)">
<b>{{aplhabet.letter}}</b>
</button>
<section ng-show="aplhabet.newdiv">functionInvoked
</section>
</div>
</div>
You need to pass $index
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<div ng-controller="MyCtrl">
<div ng-repeat="aplhabet in word track by $index">
<button style="width:50px; margin: 5px" ng-click="addDiv($index)">
<b>{{aplhabet}}</b>
</button>
<section ng-show="newdiv">functionInvoked</section>
</div>
</div>
<script>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope){
$scope.word = 'STRINGDEMO';
$scope.addDiv = function (index) {
//do your stuff here
}
}
</script>
</body>
</html>
Related
Hello everyone im trying to get the id of a div through a function in javascript like this:
<div id="txtHint" onload="getId(this);"></div>
The function is located just before </body> tag of my html page
function getId(theId) {
var name = document.getElementById(theId);
}
In the body of my html page i have a button:
<button type="button" onclick="alert(getId())">get</button>
I receive an undefined alert on clicking
How do i get the div's id?
Anyone can help?
Though I don't know the use case of this, you can pass the id to the function and return that from the function:
function getId(theId) {
var name = document.getElementById(theId);
return name.id;
}
<div id="txtHint"></div>
<button type="button" onclick="alert(getId('txtHint'))">get</button>
Update: If you want to get all id's by tag, simple pass the tag to the function and get all the id's of those element:
function getId(el) {
var element = document.querySelectorAll(el);
var id = [...element].map(i=>i.id).filter(i=>i);
return id;
}
<div id="txtHint1">First</div>
<div id="txtHint2">Second</div>
<div id="txtHint3">Third</div>
<div id="txtHint4">Fourth</div>
<button type="button" onclick="alert(getId('div'))">get</button>
The way your functions is written the only way is to have global variable
var divId = null;
function getId(div) {
divId = div.id;
}
function getId() {
alert(divId);
}
And here is my suggetions on doing it
First way is to "mark" the div at onload event and get the id of it using this "mark"
function markDiv(thisDiv) {
thisDiv.classList.add('mark')
}
function getMarkedDiv() {
var div = document.querySelector('.mark');
alert(div.id);
}
<div id="Mark" onload="markDiv(this)" class="mark"></div>
<button onclick="getMarkedDiv()">button</button>
Another way is to wrap the button and the div inside one parent
function getMySiblingId(button) {
alert(button.parentElement.firstElementChild.id);
}
<div id="Parent">
<div id="Mark"></div>
<button onclick="getMySiblingId(this)">Button</button>
</div>
Or the easiest way is to wrap button inside the desired div
function getId(btn) {
alert(btn.parentElement.id);
}
<div id="Mark">
<button onclick="getId(this)">Click me</button>
</div>
<div id="Alice">
<button onclick="getId(this)">Click me</button>
</div>
<div id="Charlie">
<button onclick="getId(this)">Click me</button>
</div>
Of course in all this scenarios i didn't assume that you want to get ids of multiple divs
so i remade the code
function divField(theDivFieldId) {
var name = document.getElementById(theDivFieldId);
return name.id;
}
html
<div id="txtHint" onload="alert(divField(this));"></div>
and nothing happens
I have this function that I am trying to get the data value of the outside div but I can't seem to get it to work, here is my code:
I want the variable test to have the value of 1000. But I get undefined.
function View() {
var test = $(this).Parent().val;
}
function Hide() {
var test = $(this).Parent().val;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-value="1000">
<a onclick="View();">View</a>
<a onclick="Hide();">Hide</a>
</div>
function View(anchor) {
var test = $(anchor).parent().data('value');
console.log(test);
}
function Hide(anchor) {
var test = $(anchor).parent().data('value');
console.log(test);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-value="1000">
<a onclick="View(this);">view</a>
<a onclick="Hide(this);">hide</a>
</div>
Here is a JQuery solution for the problem.
$('#hide').click(function() {
alert($(this).parent().data('value'));
})
$('#view').click(function() {
alert($(this).parent().data('value'));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-value="1000">
<a id="view">View</a>
<a id="hide">Hide</a>
</div>
I'm posting my html and directive code. I have two spans, which I have attached ng-click to. On ng-click I want to check the classes of their parents parent item (.parent-portlet), but what I have so far is not working correctly as all of the parent portlets get selected instead of only the current one.
<div class="parent-portlet {{portlet.class}} {{portlet.class2}}" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
<div class="portlet-titlebar" ng-click="toggleCollapsed($event)">
<span class="remove" ng-click="removePortlet(portlet)">
Remove
</span>
<span class="add-back" ng-click="addPortlet(portlet)">
Add Back
</span>
</div>
</div>
this is what I have in my directive:
scope.removePortlet = function(portlet) {
var port = $('.remove').parent().parent();
port.addClass('removed');
port.addClass('edit-portlet');
};
scope.addPortlet = function(portlet) {
var port = $('.add-back').parent().parent();
if (portlet.hasClass('removed')) {
port.removeClass('removed');
port.removeClass('edit-portlet');
}
};
The problem with this code is that var portlet catches all of the portlets(parents) and I want to catch only the one related to the click action. How can I achieve that? I tried to pass this to my jquery select like so:
var portlet = $('.add-back', this).parent().parent();
but that didn't work. Any ideas how this can be achieved?
Thanks in advance.
Pass in the $event to the ng-click like this:
<span ng-click="removePortlet($event)"></span>
Then, just modify your code like this:
scope.removePortlet = function(ev) {
var port = $(ev.target).parent().parent();
port.addClass('removed');
port.addClass('edit-portlet');
};
scope.addPortlet = function(ev) {
var port = $(ev.target).parent().parent();
if ($(ev.target).hasClass('removed')) {
port.removeClass('removed');
port.removeClass('edit-portlet');
}
};
Grabbing the "event's target" will ensure that you are only addressing the item that was actually clicked. And note that angular uses $event to pass the event to a function.
I would also clean it up a bit combining the class modification lines and targeting the specific parent (in case you ever modify the DOM) using .closest():
scope.removePortlet = function(ev) {
var port = $(ev.target).closest('.parent-portlet');
port.addClass('removed, edit-portlet');
};
scope.addPortlet = function(ev) {
var port = $(ev.target).closest('.parent-portlet');
if (portlet.hasClass('removed')) {
port.removeClass('removed, edit-portlet');
}
};
You can inject the $element to your controller, then, use it as the context for the $ selector.
angular.module('app', []).controller('ctrl', function($scope, $element) {
$scope.addPortlet = function(portlet) {
console.log($('.add-back', $element));
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="parent-portlet">
<div class="portlet-titlebar" ng-click="toggleCollapsed($event)">
<span class="remove" ng-click="removePortlet(portlet)">
Remove
</span>
<span class="add-back" ng-click="addPortlet(portlet)">
Add Back
</span>
</div>
</div>
</div>
For more info about it
Use ng-class instead. Here's an example of changing background colors with classes:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.portlet = {
classes: {
"parent-portlet": true,
"edit-portlet": false,
"removed": false
}
}
$scope.removePortlet = function(portlet) {
portlet.classes.removed = true;
portlet.classes["edit-portlet"] = true;
};
$scope.addPortlet = function(portlet) {
portlet.classes.removed = false;
portlet.classes["edit-portlet"] = false;
};
});
/* Put your css in here */
.parent-portlet {
background-color: #ccc;
padding: 20px;
}
.parent-portlet.removed {
background-color: #c00;
}
.parent-portlet button {
padding: 10px;
margin: 0 10px;
}
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<body ng-controller="MainCtrl">
<div ng-class="portlet.classes">
<div class="portlet-titlebar">
<button class="remove" ng-click="removePortlet(portlet)">
Remove
</button>
<button class="add-back" ng-click="addPortlet(portlet)">
Add Back
</button>
</div>
</div>
</body>
</html>
My view has a button and the view is looped.so it has raws.
when i click the button of a single raw i need to color that button.
so i added a onclick="select_Button(<?php echo $rawID?>)" to the raw's button in my view
select_Button is my funtion in js
function select_Button(rawNumberOfVote) {
var RawNumber = rawNumberOfVote;
alert ("Form submitted successfully" + RawNumber);
var upVote = document.getElementById("up_vote");
upVote.style.background = "green";
}
like above i send the rawID to the funtion.
how can i edit this line to accept the view called up_vote in that particular raw id that i got from parameter.
var upVote = document.getElementById("up_vote");
becuz if i only use this line it will color the first raw's button instead the one i wanted
Thank you
you can use data attribute in your html referencing to this page and this page. and retraive with this this jquery code snippet:
$("[data-test ='my value']")
or this code snnipet in javascript:
document.querySelectorAll(".example").find(function(dom){
return dom.dataset.test == "expected-value"
});
Update:
accourding to this page querySelectorAll return nodeList and NodeList are not array and we cannot use find method so I change my answer to this code:
<html>
<body>
<div class="post" data-key="1">
<lable>test</lable>
<button type="button" onclick="upvote(1)">up vote</button>
</div>
<div class="post" data-key="2">
<lable>test</lable>
<button type="button" onclick="upvote(2)">up vote</button>
</div>
<div class="post" data-key="3">
<lable>test</lable>
<button type="button" onclick="upvote(3)">up vote</button>
</div>
</body>
</html>
<script type="text/javascript">
var upvote = function(id) {
var nodes = document.querySelectorAll(".post");
console.log(nodes.length);
for(i = 0 ; i < nodes.length ; i++){
console.log(nodes[i].dataset.key);
if (nodes[i].dataset.key == id)
nodes[i].style.backgroundColor = "red";
}
};
</script>
I asked this question but the specific question I'm asking has changed dramatically.
I have a piece of code:
<div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
<h1 ng-click="pings.press()">asdf</h1>
</div>
This code is injected into two html pages. One page already calls PingsCtrl. The other doesn't. I'm really trying to keep this code DRY and I only want to have one reference of the code above.
How can I write the code above to generate ng-controller if PingsCtrl hasn't already instantiated.
Here are the two html pages.
HTML
// First page
<html ng-app="coolApp">
<div ng-controller="PingsCtrl as pings">
<div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
<h1 ng-click="pings.press()">asdf</h1>
</div>
</div>
</html>
// Second page
<html ng-app="coolApp">
<div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
<h1 ng-click="pings.press()">asdf</h1>
</div>
</html>
Javascript is here:
angular.module('coolApp', [])
.controller('PingsCtrl', function() {
var vm = this;
vm.press = function() {alert(123)};
})
What's wrong and how do I fix this?
Just use a service. It's really the intended structure for having common data and functionality between pages.
Part of the problem with what you were attempting is, whether or not you manage to preserve the controller, Angular has its own management that won't follow you with that, and will be refreshing components without you. You'll run into things like a $scope that doesn't actually match the page you're looking at, and it ends up causing more problems than it's worth.
I do have a solution but I also echo other people's concerns about the approach. You may want to have a global controller that you drop on the body for things that can happen anywhere and in most of the other controllers and just call through that. Eg
<body ng-controller="GlobalCtrl as gc">
<h1 ng-click="gc.pingPress()"></h1>
</body>
Anyway here is what I came up with.
<div ng-if="pings">
<h1 ng-click="pings.press()">asdf</h1>
</div>
<div ng-if="!pings">
<div ng-controller="PingsCtrl as pings">
<h1 ng-click="pings.press()">asdf</h1>
</div>
</div>
This will work if it is dropped inside or outside of an existing PingsCtrl.
Here is a plunker.
https://plnkr.co/edit/4x0kSazcg0g0BsqPKN9C?p=preview
Please, check my solution to see how to share data between controllers
var app = angular.module('myApp', []);
app.controller("aCtrl", function ($scope, PingList) {
$scope.addPing = function() {
PingList.add('Ping A');
};
});
app.controller("bCtrl", function ($scope, PingList) {
$scope.addPing = function() {
PingList.add('Ping B');
};
});
app.factory('PingList', function () {
var pings = ['Ping1', 'Ping2'];
return {
add: function(ping) {
pings.push(ping);
},
get: function () {
return pings;
}
};
});
app.directive('pingList', function(PingList) {
return {
restrict: 'EA',
link: function($scope) {
$scope.pings = PingList.get();
$scope.press = function(ping) {
alert(ping);
}
},
template: '<ul><li ng-repeat="ping in pings" ng-click="press(ping)">{{ping}}</li></ul>'
};
});
a, li {
cursor: pointer;
}
a {
color: blue;
text-decoration: underline;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="aCtrl" style="float: left">
<a ng-click="addPing()">click to add A ping</a>
<ping-list></ping-list>
</div>
<div ng-controller="bCtrl" style="float: right">
<a ng-click="addPing()">click to add B ping</a>
<ping-list></ping-list>
</div>
<div style="clear: both"></div>
</div>