How to pass AngularJS ng-repeat Variable to Javascript click event - javascript

I would like to know how to pass Angular ng-repeat variable to my Javascript onclick event
My angular repeater
<div class="data" data-ng-repeat="sub in subs" >
<button onclick="ConfirmDialog(sub.SubID)">Cancel</button>
{{ sub.someOtherProperty}}
{{ sub.someOtherProperty}}
{{ sub.someOtherProperty}}
</div>
My script function
<script type='text/javascript'>
function ConfirmDialog(subID) {
console.log('Succesfully submitted id: ', subID);
});
</script>
The error : sub is not defined (in the onclick() call from the button element) all other properties show as expected.

You are running straight javascript onclick instead of ng-click.
move confirmDialog into your controller and ng-click can attach to it.
<div class="data" data-ng-repeat="sub in subs" >
<button ng-click="ConfirmDialog(sub.SubID)">Cancel</button>
</div>
$scope.ConfirmDialog = function (subID) {
console.log('Succesfully submitted id: ', subID);
});

If you don't want to use ng-click, you still have a chance! Try the following
<tr ng-repeat="supplier in suppliers" id="{{supplier.id}}">
<button onclick="readVariable(this);">
</tr>
<script>
function readVariable(elem){
id = elem.parentNode.id;
console.log(id); //it works!
}
</script>

You should use ng-click instead in order to access the ng-repeat variable
<button ng-click="ConfirmDialog(sub.SubID)">Cancel</button>

Related

jQuery and jinja2 .data("") returning undefined

the no of items are displayed along with an edit button with each item on clicking edit button the data of button is retrieved in jQuery function but I am getting undefined not the data-id
<div>
{% for stock in part_temp.part_stock_set.all %}
{% with id="list"|concatenate:stock.id btn_id="btn"|concatenate:stock.id %}
<div id="{{ id }}">
{{ stock.entry_date}}
{{ stock.supplier }}
{{ stock.amount }}
{{ stock.remaining }}
<button id="{{ btn_id }}" type="submit" data-id="{{stock.id}}" onclick="display_popup()" style="position: absolute; right:0;" >edit</button>
<hr>
</div>
<br>
{% endwith %}
{% endfor %}
</div>
instead of {{stock.id}} I also tried passing other string but still got undefined
<script type="text/javascript">
function display_popup() {
var name = $(this).data("id");
window.alert(name);
}
</script>
instead of .data() also tried other like .text() .Val but got nothing
As of current code; this in the display_popup function refers to window object thus its not returning the desired value.
Pass current element context this in the inline click handler
<button onclick="display_popup(this)">
Script, Accept it as parameter and use it to get data
function display_popup(elem) {
var name = $(elem).data("id");
window.alert(name);
}
However, I would recommend you to use unobtrusive event handler. Assign a common class to button.
<button class="edit" data-id="{{stock.id}}" >edit</button>
script
$(function(){
$('.edit').on('click', display_popup); //this will set as context so you existing method will work
});
$(function() {
$('.edit').on('click', display_popup); //this will set as context so you existing method will work
function display_popup() {
var name = $(this).data("id");
window.alert(name);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="edit" type="submit" data-id="1">edit</button>
Set the context of function with current element using .bind()
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
function display_popup() {
var name = $(this).data("id");
window.alert(name);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button type="submit" data-id="1" onclick="display_popup.bind(this)()">edit</button>
first, inspect the elements and functions. Try to inspect the HTML and see if the data you need has value. Try to console.log(this) on display_popup function, You should see the button.
If everything is ok, then try to use $(this).data(). It will returns a object with all the data of the element.
If it didn't work (or this case is better for you), use:
$(this).attr('data-id')
this will return the data-id attribute value.
If none of this works, check your jquery version, but i belive the attr will work fine.
----EDIT----
this is undefined on the display_popup function. you need to use onclick="display_popup(this)" and then use the parameter to get the element attributes

alert value of button by onClick

I have a page with a lots of buttons from PHP output with each buttons having different values:
<button class='add' value=".$row['cat_no']." onClick='addItem(value)'>Add To Cart</button>
$row['cat_no'] is data from mysql.
I want to check the button's value when I click it, so I use native JS below:
<script>
function addItem(value) {
alert("this.value");}
</script>
It is not working...it just return this.value. In this case I don't think it is suitable to assign Id to getElementbyId, Pls help to check my mistake or suggest solution. Thanks.
Pls: I dont want to use JQUERY, just native JS.
Use alert(elmt.value); like below. you should pass this to the function
<button class='add' value="test value" onClick='addItem(this)'>Add To Cart</button>
<script>
function addItem(elmt) {
alert(elmt.value);
}
</script>
the code below helps you retrieve the value of the element that triggered the event:
<button class='add' value="test value" onClick='addItem(this)'>Add To Cart</button>
<script>
function addItem(sender) {
alert(sender.value);
}
</script>
However, this is filled with code smells.
I would suggest doing the code below
<button id='add-to-cart' class='add' value="test value">Add To Cart</button>
On a separate JS file:
(function() {
function _onLoad() {
var addToCartButton = document.getElementById("add-to-cart");
addToCartButton.addEventListener("click", _onAddToCartClicked);
}
function _onAddToCartClicked() {
var sender = this;
alert(sender.value);
}
document.addEventListener("DOMContentLoaded", _onLoad, false);
})();
This approach ensures that:
Concerns are separated between HTML and JS
External JavaScript file would be cached which results to faster page load time.
UI would render faster since there are no inline scripts
Global namespace won't be polluted
You don't really need this in your function, just use value. And also remove double quotes, because you need to alert function's parameter, not string, like this:
function addItem(value) {
alert(value);
}
Here is the working example:
function addItem(value) {
alert(value);
}
<button class='add' value="yourValue" onClick='addItem(value)'>Add To Cart</button>
Or you can pass the element to function using this, and then get the needed attribute value from addItem method:
function addItem(item) {
alert(item.value);
}
<button class='add' value="yourValue" onClick='addItem(this)'>Add To Cart</button>

How do I get javascript to fire after all angular fields have been populated?

I have a Angular application hosted on Azure. I do not have access to the controller, but I can change the HTML. I want to add a javascript function to convert decimals to fractions. I am able to get the code to work on a button press, but I'm unable to get the javascript function to be called when the page loads. If I try to call the function in the equivalent of a document.ready, I get a null when I try to find the text elements. I'm new to Angular, but I'm guessing it hasn't fully populated the data elements on the page when document.ready is called, but it has by time there's a button click. How can I get this code to work without clicking a button?
Here's the HTML code:
<md-dialog aria-label="{{ currentRecipe.Name }}" ng-cloak class="pretty-recipe">
<md-toolbar layout="row">
<div class="md-toolbar-tools">
<h3 flex>{{ currentRecipe.Name }}</h3>
<h4>MM Score: XX</h4>
</div>
<span flex></span>
<md-button ng-click="close()" aria-label="Close window">
<md-icon>close</md-icon>
</md-button>
</md-toolbar>
<md-dialog-content oncomplete="buttonConvert">
<div id="divDialog" class="md-dialog-content" layout="row">
<h4>Ingredients</h4>
<table class="component-ingredients-container">
<tr ng-repeat-start="component in currentRecipe.Components"
ng-show="component.Name">
<td class="component-name-cell">
<span class="component-name">{{component.Name}}</span>
</td>
</tr>
<tr ng-repeat-end ng-repeat="ingredient in component.Ingredients">
<td>
<span class="ingredient-amount" id="amount-{{$index}}">{{ingredient.Amount}}</span>
<span class="ingredient-unit">{{ingredient.Unit}}</span>
<span> {{ingredient.Lookup.Name}}</span>
<div class="ingredient-preparation" ng-show="ingredient.Preparation">
<span> {{ingredient.Preparation }}</span>
</div>
</td>
</tr>
<tr>
<td>
<button id='btnConvertToFractions' onclick="buttonConvert()">Convert to Fractions</button>
</td>
</tr>
</table>
</div>
</md-dialog-content>
<md-dialog-actions layout="row">
<md-button class="md-primary" ng-click="refresh()" aria-label="Refresh"
ng-show="currentUser.hasRole('RecipeMaintainer')">
<md-icon>refresh</md-icon>
Refresh
</md-button>
<span flex></span>
<md-button class="md-primary" ng-click="print()" aria-label="Print">
<md-icon>print</md-icon>
Print
</md-button>
</md-dialog-actions>
If I add the following code in a script tag at the bottom of the HTML page, a button click will call my Fraction function like I want:
<script>
function buttonConvert() {
try {
console.log("Convert started");
var divs = document.querySelectorAll('.ingredient-amount');
console.log(divs);
[].forEach.call(divs, function (div) {
console.log("Before: " + div.textContent);
div.textContent = Fraction(div.textContent);
console.log("After: " + div.textContent);
});
console.log("Convert finished");
}
catch (ex) {
console.log("Error: " + ex);
}
};
However, I need that function to be called when the page is loaded. I've tried these examples, but I get a null set when looking for elements with the class ingredient-amount:
A docReady function from https://github.com/jfriend00/docReady/commit/defe8c06f21c86bd5cf529444d8fe5879dca03ca
docReady(function () {
buttonConvert();
});
Checking the ready state.
if (document.readyState === "complete") {
buttonConvert();
}
An on window load event.
$(window).bind("load", function () { console.log("started"); buttonConvert();});
An angular element ready. I tried this with various element names including document.
angular.element(document).ready(function () {
buttonConvert();
});
jquery document.ready. I get a "$ is not defined" error. I tried adding
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js">
</script>
but, I always got the same error. Thinking angular and jquery are conflicting? I don't really know; just assuming jquery won't work for this project.
$document.ready(function () {
buttonConvert();
});
I've probably tried some others I've found online, but didn't write down.
So how do I call buttonConvert() at a time where it's going to find elements with the ingredient-amount class?
Thank you!
Is it possible for you to use Number filter that comes with angular?
{{ number_expression | number : fractionSize}}
{{ingredient.Amount | number : 2}}
It seems like my code to select elements with the class ingredient-amount was correct, but that it was running before all the data elements were filled in. That is, the ng-repeat section hadn't "repeated" yet. I found that if I used an event to run on document ready and then used a timeout that it gave the page the time to fill in each of the amounts.
Here's my solution:
<script>
function buttonConvert() {
try {
var divs = document.querySelectorAll('.ingredient-amount');
[].forEach.call(
divs
, function (div) {
//div.textContent = Fraction(div.textContent);
div.textContent = mixin.getFractionFromDecimal(div.textContent);
}
);
}
catch (ex) {
console.log("Error: " + ex);
}
};
angular.element(document).ready(
setTimeout(
function () {
buttonConvert();
}
, 2000));
</script>

How "Data" can help me

I'm doing a web game with javaScript and KnockoutJs library.
In my html file I have a array foreach, and the number that this array saves, is the same number of buttons that a I have to draw on the page. Like this:
<strong data-bind = "foreach: cena1.opcoes">
<button data-bind="click: $parent.teste">Opcão</button>
<font color="red"><strong data-bind="text: conteudo"> </strong></font><br>
What I want to know is, how will I know which button the player selected?
I put data like a parameter on my button function, but I don't know how this works. like this:
object.teste = function(data) {
}
You can call the function this way:
<button data-bind="click: function() { $parent.teste($data); }">Opcão</button>
or
<button data-bind="click: function() { $parent.teste($data/* here can be any arguments available in the current binding context */); }">Opcão</button>
Update
By default the first parameter is being passed to the click handler function is the current view model - $data in the current binding context.
For more details and advanced scenarios you can check the Knockout JS documentation.
The click binding passes the current item to the bound function.
var vm = {
items: [1, 2, 3],
click: function(data) {
alert('You clicked: ' + data);
}
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach:items">
<button data-bind="click:$parent.click">Click</button>
</div>

How to display value of a ViewBag in my view with a JS function?

I want to display the data from a ViewBag in my View with Javascript. Here is my code.
View
<span id='test'></span>
Javascript
function myFunction()
{
$('#test').text('#ViewBag.Test');
}
When myFunction() is called I get the text #ViewBag.Test but not his value. How can I fix this ?
You need to place your JavaScript which takes the #ViewBag.Test value in a page which is interpreted by the Razor view engine. My guess is that this is currently not the case.
If you want to keep your javascript codebase separate from the view (which is entirely reasonable) you can use a global variable:
// in the view:
var testText = '#ViewBag.Test';
// in external js
function myFunction() {
$('#test').text(window.testText);
}
Alternatively, you can use a data-* attribute:
<span id='test' data-text="#ViewBag.Test"></span>
// in external js
function myFunction() {
$('#test').text(function() {
return $(this).data('text');
});
}
What you should be ideally doing is passing the data to the view with a view model. Have a property to store that value you want to pass. For example. Let's think about a page to show the customer details and you want to get the last name in your javascript variable.
Your GET action method
public ActionResult View(int id)
{
var vm=new CustomerViewModel();
vm.LastName="Scott"; // You may read this from any where(DAL/Session etc)
return View(vm);
}
and in your view which is strongly typed to your view model.
#model CustomerViewModel
<div>
Some Html content goes here
</div>
<script type="text/javascript">
var lastName="#Model.LastName";
//Now you can use lastName variable
</script>
EDIT : (As per the question edit) To show the content on some event (ex : some button click), Store the value somewhere initially and then read it as needed and set it wherever you want.
#model CustomerViewModel
<div>
<span id="content"></span>
#Html.HiddenFor(s=>s.LastName)
<input type="button" id="btnShow" value="Show content" />
</div>
<script type="text/javascript">
$(function(){
$("btnShow").click(function(e){
$("#content").html($("#LastName").val());
});
});
</script>
Firstly make sure your ViewBag.Test does got a value, then use a div tag instead of a span and add the following code:
<script type="text/javascript">
$(document).ready(function () {
StartRead();
});
function StartRead() {
document.getElementById("test").innerHTML = '#ViewBag.Test';
}
</script>

Categories