I have a table containing multiple rows of data. The user can scroll through each row, click a row, and be prompted to do something with that row (update, delete, etc).
I'm able to get the id of the clicked row (the id is significant as it's the id of the model object) with Javascript and make an AJAX call to the server with the id however I can't figure out how to redirect to a page after the first server call without making a second trip to the server as AJAX needs a response.
So I'm trying to accomplish this without AJAX. Is there a way to pass the id of the row into the url (in the a-tag) of the modal below? Or is there a better pattern to accomplish this that I'm missing. This problem seems like it must have an obvious solution and I'm overthinking it...
Here's the pertinent code for my table.
Edit: I'm also using Django for my backend/template engine.
<tbody id="trip-request-table">
{% for key in need_trips %}
<tr id={{key.trip_ptr_id}} onClick="updateRow(this.id)">
<td>{{key.created|date:'Y-m-d'}}</td>
<td>{{key.user.name}}</td>
<td>{{key.arrival_date|date:'Y-m-d'}}</td>
</tr>
{% endfor %}
</tbody>
Here's the Javascript that grabs the id and fires a modal:
function updateRow(id) {
//alert('id: ' + id);
var rowId = id;
var modal = $('#manage-trip');
var row = document.getElementById(id);
var cells = row.getElementsByTagName('td');
var arrivalCity;
var departureDate;
for (var i =0; i < cells.length; i++) {
if(i == 4) {
departureDate = moment(cells[i].innerHTML).format('MMMM Do, YYYY');
} else if(i == 6) {
arrivalCity = cells[i].innerHTML;
}
}
modal.find('.modal-body').text('Would you like to update your trip to ' + arrivalCity + ' on '
+ departureDate + '?');
//updateRow.find('.modal-body input').val(id);
modal.val(id);
console.log('show modal');
modal.modal('show');
console.log('trip id: ' + id);
$("#update-trip").off().click(function(event) {
$('#manage-trip').modal('hide');
var contentType = "application/x-www-form-urlencoded";
var processData = true;
var endpoint = "{% url 'trips:updateTripGet' pk=1 %}";
var payload = false;
updateTrip(contentType, processData, endpoint, payload);
});
}
Here's the modal code:
<div class="modal" id="manage-trip" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit your trip</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
Update
<!--<button type="button" class="btn btn-primary" id="update-trip">Update</button>-->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#delete-trip">Delete</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The way I solved this was by having the modal trigger this block of code:
$("#update-trip").off().click(function(event) {
$('#manage-trip').modal('hide');
var contentType = "application/x-www-form-urlencoded";
var endpoint = "{% url 'members:updateTrip' %}";
var payload = false;
//updateTrip(contentType, processData, endpoint, payload);
submitForm(contentType, endpoint, rowId);
});
That code block calls a function that dynamically creates a form and submits it to the server. I guess this is just another obvious solution to most web developers but I'm noob af. I'm sure I'll clean this up some just stoked it works.
The nice thing about this solution is you avoid having to create forms in each table row, etc.
function submitForm(contentType, endpoint, rowId) {
var form = document.createElement("form");
var element1 = document.createElement("input");
var element2 = document.createElement("input");
form.method = "POST";
form.enctype = contentType;
form.action = endpoint;
element1.type = 'hidden';
element1.value= rowId;
element1.name= "trip_id";
form.appendChild(element1);
element2.type = 'hidden';
element2.value= '{{ csrf_token }}';
element2.name= 'csrfmiddlewaretoken';
form.appendChild(element2);
document.body.appendChild(form);
form.submit();
}
Related
The relevant Javascript follows below, but in short, the archive button works while the delete button does not. I've already tried moving the event handler to a different file which the HTML calls using script tags to see if that makes a difference, but it doesn't seem to, although I'm unsure if it's broken in the same way. Additionally, the actual functions associated with each event handler are practically the same, so it seems reasonable to rule out that the function itself causes the problem. Why are the two buttons performing differently?
const mongo = require('mongodb');
const config = require('../../javascripts/config.js'); //databaseAddress can now be found at config.databaseAddress()const mongo = require('mongodb');
const MongoClient = mongo.MongoClient;
const url = config.databaseAddress();
$(document).ready(function () {
$('#navbar-userSearch').addClass('active');
$('.archive-button').click(function () {
var id = $(this).attr('id').split('-').slice(-1)[0] ;
console.log('id', id);
var username = $('#username-' + id).val();
var csrf = $('#csrf').val();
var action = $(this).attr('id').split('-')[0];
console.log('username', username);
$.ajax({
url: '/'+action+'/'+username,
type: 'PUT',
data: {username: username, _csrf: csrf},
success: function(data) {
if (data.success) {
addMessage(data.message, true);
if (typeof data.redirect === 'string') {
setTimeout(function(){
window.location = data.redirect;
}, 2500);
}
} else {
addMessage(data.message, false);
}
},
error: function(err) {
addMessage('A network error might have occurred. Please try again.', false);
}
});
});
$('.delete-button').click(function() {
console.log("stop pushing my buttons");
var id = $(this).attr('id').split('-').slice(-1)[0] ;
console.log('id', id);
var username = $('#username-' + id).val();
console.log('username', username);
MongoClient.connect(url, { useNewUrlParser: true }, (err, client) => {
const db = client.db("paxpopulidb");
const id_query = {_id: id};
const username_query = db.collection("users").find(id_query, {_id: 0, username: 1});
const username = username_query.username;
if (username) {
if (username === "superadmin"){
console.log("You cannot delete the superadmin account.");
} else {
db.collection("registrations").deleteOne(username_query);
db.collection("users").deleteOne(username_query);
db.collection("schedules").deleteOne(username_query);
console.log("Deleted " + username + " from database.");
}}})
})});
The HTML uses Handlebars for templating and is as follows:
{{#each users}}
<div class='col-xs-12 col-ms-6 col-sm-4 col-md-3 col-lg-4 user-container tile-container' id='user-container-{{_id}}'>
<div class='tile user-tile' name="user-{{_id}}" data-id='{{_id}}'>
<div class='tile-icon' style='float: left'><img class='icon' src="/images/user.gif"></img></div>
<div class='user-header tile-header'>
<a data-toggle="modal" data-target='#user-modal-{{_id}}'>
<h4 class='tile-title'>{{#if fullName}}{{fullName}}{{else}}{{firstName}} {{lastName}}{{/if}}</h4>
</a>
<p class='tile-subtitle'>{{role}}<h class='small-text'>{{#if archived}}(archived){{/if}}</h></p>
</div>
</div>
<div id="user-modal-{{_id}}" class="user-item-modal modal fade" role="dialog">
<div class="modal-messages"></div>
<div class="modal-dialog modal-xs">
<div class="modal-content">
<div class="modal-header modal-title">
<button type="button" class="close" data-dismiss="modal">×</button>
{{#if fullName}}{{fullName}}{{else}}{{firstName}} {{lastName}}{{/if}}'s Profile
</div>
<div class="modal-body">
{{> profileTable}}
</div>
</div>
</div>
</div>
<div>
<input id='username-{{_id}}' type="hidden" value="{{username}}"></input>
<input id='requestToken-{{_id}}' type="hidden" value="{{requestToken}}"></input>
<input id='csrf' type="hidden" name="_csrf" value="{{csrfToken}}">
<center>
{{#isRegularUser role}}
<button id='registration-button-{{_id}}' class='btn btn-info btn-hg registration-button'>View/Edit Registration</button>
<button id='schedule-button-{{_id}}' class='btn btn-info btn-hg schedule-button'>View/Edit Schedule</button>
{{/isRegularUser}}
{{#ifNot archived}}
<button id='archive-button-{{_id}}' class='btn btn-warning btn-hg archive-button'>Deactivate</button>
{{else}}
{{/ifNot}}
{{#isRegularUser role}}
<button id='delete-button-{{_id}}' class='btn btn-danger btn-hg delete-button'>Delete User</button>
{{/isRegularUser}}
</center>
</div>
</div>
{{/each}}
In short, the above makes a small box with appropriate buttons for each user depending on their role attribute, but the only working button so far is archive-button (no event handlers exist for the other two yet) However, the delete-button actually displays, it's just that clicking it does nothing.
Your bracketing is wrong. You have the delete button event handler inside the archive button click handler. So the delete handler isn't added until you click on an archive button (and if you click on archive multiple times, the delete buttons will execute their code multiple times).
You would see this if you'd indented your code correctly (every programming editor has options to automate this for you).
It should be:
$(document).ready(function() {
$('#navbar-userSearch').addClass('active');
$('.archive-button').click(function() {
var id = $(this).attr('id').split('-').slice(-1)[0];
console.log('id', id);
var username = $('#username-' + id).val();
var csrf = $('#csrf').val();
var action = $(this).attr('id').split('-')[0];
console.log('username', username);
});
$('.delete-button').click(function() {
console.log("stop pushing my buttons");
var id = $(this).attr('id').split('-').slice(-1)[0];
console.log('id', id);
var username = $('#username-' + id).val();
console.log('username', username);
});
});
I'm trying to take input from the user from a drop-down list. I've used javascript to take input of dynamic size and then stored the input in a variable using appendChild. Now I want to send this variable back to django views where I can perform some operations on it.
I've tried using getlist and get function in django but am not able to figure out how to get the variable.
<form method = "POST" name = "myForm" onsubmit = "return validateForm()">{% csrf_token %}
<p>Entry Condtion:</p>
<div id ="entry-parameters"></div>
<button type="button" onclick= "add_entry_parameter()" class="btn btn-primary m-t-15 waves-effect">Add a new Entry Condition</button>
<button type= "button" onclick= "remove_entry_parameter()" class= "btn btn-primary m-t-15 waves-effect">Remove Entry Condtion</button>
<br>
<p>Exit Condtion</p>
<div id = "exit-parameters"></div>
<button type="button" onclick= "add_exit_parameter()" class="btn btn-primary m-t-15 waves-effect">Add a new Exit Condition</button>
<button type= "button" onclick= "remove_exit_parameter()" class= "btn btn-primary m-t-15 waves-effect">Remove Exit Condtion</button>
<br>
<br>
<br>
<input type="submit" value="submit" >
</form>
<script>
var list = ['open' , 'close' , 'high', 'low'];
var addField = document.getElementById('addField');
parameters= document.getElementById('entry-parameters');
exit_parameters= document.getElementById('exit-parameters');
parameters.setAttribute("name" , "parameters" );
exit_parameters.setAttribute("name" , "exit_parameters");
function remove_entry_parameter()
{
parameters.removeChild(parameters.lastElementChild);
}
function add_entry_parameter()
{
var _form = document.body.appendChild(document.createElement('form')),
_input = _form.appendChild(document.createElement('input')),
_condition = _form.appendChild(document.createElement('input')),
_input2 = _form.appendChild(document.createElement('input')),
_datalist = _form.appendChild(document.createElement('datalist'));
_cond_list = _form.appendChild(document.createElement('datalist'));
_input.placeholder = "First Parameter";
_input.list = 'exampleList';
_input.setAttribute('list','exampleList')
_input.datalist_id = 'exampleList';
_input2.placeholder = "Second Parameter";
_input2.list = 'exampleList';
_input2.setAttribute('list','exampleList')
_input2.datalist_id = 'exampleList';
_condition.placeholder = "Condition";
_condition.list = 'conditionList';
_condition.setAttribute('list','conditionList')
_condition.datalist_id = 'conditionList';
_datalist.id = 'exampleList';
_cond_list.id = 'conditionList';
var list = ['open' , 'close' , 'high' , 'low' , 'vol'];
var cond_list = ['greater than', 'less than' , 'crossed above' , 'crossed below', 'equal to'];
for (var i = 0; i < list.length ; i++) {
var _option = _datalist.appendChild(document.createElement('option'));
_option.text =list[i];
};
for (var i = 0; i < cond_list.length ; i++) {
var _option = _cond_list.appendChild(document.createElement('option'));
_option.text = cond_list[i];
};
parameters.appendChild(_form);
}
// I've written a similar code for exit_parameters
</script>
def get_data(request):
if request.method == 'POST':
entry_data = request.POST.get('parameters')
exit_data = request.POST.get('exit_parameters')
print(entry_data)
print(exit_data)
return render(request, 'get_data.html' , {})
Your function add_entry_parameter starts by creating a new form on the page. You almost certainly want ONE form on the page -- no need to create new ones.
The selection made in the dropdown should be visible in the DOM (inspector) with a unique field name (it doesn't make sense for all fields on the form to have the same name, as you stated in a response above) -- all fields must have a unique name.
Once you've verified that the value in an existing, uniquely named field is updated when the user makes a selection, it should come through in the POST.
I consider my database quite well nested. And for each data I saved it using the current user uid, then I push it into firebase which it create a unique pushid, so when I want to get the data, it always just get one data which is not from the unique pushid, but the user uid is correct. How do I get the correct data from the correct pushid?
My database that I want to save the information: https://imgur.com/a/tird0jD
My database that I retrieve the information that I want to save in the other node of the database: https://imgur.com/a/50f1M8W
As you notice in the picture of the database, the uid and pushid are retrieve correctly, but the data inside is retrieve wrongly and when I try for all, it seems to be returning all the same data.
Below is my JS code:
function choose() {
assign(document.getElementById("updateUserID").value, document.getElementById("updateID").value,
document.getElementById("person").value);
}
var rootRef2 = firebase.database().ref('Admin/Person In Charge/Towing');
select = document.getElementById('person');
var opt1 = document.createElement('Option');
opt1.value = "-Select-";
opt1.innerHTML = "-Select-";
select.appendChild(opt1);
//Retrieve P-I-C data from Firebase
rootRef2.on("child_added", function (pericRecord) {
var opt = document.createElement('Option');
opt.value = pericRecord.val().Name;
opt.innerHTML = pericRecord.val().Name;
select.appendChild(opt);
});
function showModal(userId, pushId) {
$('#modal').modal("show");
document.getElementById("updateID").value = pushId;
document.getElementById("updateUserID").value = userId;
}
function assign(userId, pushId, x) {
var person = x;
var rootRef3 = firebase.database().ref('Users/Towing Request/' + userId)
rootRef3.on('child_added', function (snapshot) {
document.getElementById("updateID").value = pushId;
document.getElementById("updateUserID").value = userId;
firebase.database().ref('Admin/AssignCarTowing/' + person +"/"+userId +"/"+pushId)
.update({
CustUID: userId,
CustName: snapshot.val().Name,
CustCarModel: snapshot.val().CarModel,
CustCarNumber: snapshot.val().CarNumber,
CustContactNo: snapshot.val().ContactNo,
CustLocation: snapshot.val().BreakdownLocation,
CustBDTD: snapshot.val().TowingDateandTime
})
});
firebase.database().ref('/Users/Towing Request/' + userId + "/" + pushId)
.update({ PersonInCharge: person, Status: "Assigned" });
window.alert("Updated to Assigned with Person In Charge");
firebase.database().ref('/Users/Towing Request/' + userId + "/" + pushId).once('value').then(function (snapshot) {
//document.getElementById('name').value = snapshot.val().Name;
//document.getElementById('email').value = snapshot.val().Email;
//document.getElementById('peric').value = snapshot.val().PersonInCharge;
//document.getElementById('status').value = snapshot.val().Status;
window.alert("Retrieved");
location.reload();
});
}
My html code where I choose who to save into:
<div class="modal fade" id="modal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Choose Person In Charge</h4>
</div>
<div class="modal-body">
<input type="text" id="updateID" />
<input type="text" id="updateUserID" />
<select id="person" onchange=choose()>
</select>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
I tried every possible answer from all the searches I got, but still no luck.
I manage to solve this myself by trial and error of the code. Below is the code that help me to solve this problem.
function assign(userId, pushId, person) {
var rootRef3 = firebase.database().ref('Users/Towing Request/' + userId);
rootRef3.on('value', function (snapshot) {
console.log(snapshot.key)
firebase.database().ref('Admin/AssignCarTowing/' + person + "/" + userId + "/" + pushId)
.set({
CustUID: userId,
CustName: snapshot.child(pushId).val().Name,
CustCarModel: snapshot.child(pushId).val().CarModel,
CustCarNumber: snapshot.child(pushId).val().CarNumber,
CustContactNo: snapshot.child(pushId).val().ContactNo,
CustLocation: snapshot.child(pushId).val().BreakdownLocation,
CustBDTD: snapshot.child(pushId).val().TowingDateandTime
})
});
firebase.database().ref('/Users/Towing Request/' + userId + "/" + pushId)
.update({ PersonInCharge: person, Status: "Assigned" });
window.alert("Updated to Assigned with Person In Charge");
location.reload();
}
Only the function Assign, is changed.
Hello all I just want to say thank you in advance. I have a few issues that I would like to address with my shopping cart page. This application is made in flask.
I have a cart that dynamically populates rows in a table with data from a Restful API created with python. At the moment it can also add the prices within the API and display it as the subtotal's html. I can also hit the delete button next to the item and it deletes that particular element out of the API. The issue is I need to be able to update the subtotal html upon deleting the item.
Yes I can hit the delete button and upon refreshing the page it will show the correct subtotal but this is unrealistic.
Upon adding and deleting items in cart I also have a badge on the shopping cart icon in the upper right hand corner that increments according to how many elements are in API. Once I figure out issue with (problem labeled 1) I can figure out how to make the badge decrease upon item deletion. My main issue here is the cart shows no badge upon moving to different tabs of the website. The JS is linked to the base html, but I guess since the java script is not running on those particular pages it's not going to show. Not to sure how to work around this.
If there are no items in cart I would like to hide the subtotal html and order button. But for some reason I can't get it to toggle and don't know where I should put the code to check if there are no items in API.
I'm probably asking too much but if possible please help if you may have any insight. I'll be attaching the code below for javascript, my flask python route, and the html for the cart page.
Pricing pricing.html
p{% extends 'base.html' %}
{% block content %}
<h1>Pricing</h1>
<div class="row">
<div class="container col-sm-6">
<div class="container border">
<table id='table'>
<thead>
<th><h5>Equipment</h5></th>
<th "><h5>Price</h5></th>
</thead>
{% for quip in pricing %}
<tr style="height:25px;" class="border">
<td id='pricewidth'>{{quip}}</td>
<td id='pricewidth' style='text-align:center;'>{{pricing[quip]}}</td>
<td ><button type="button" name="button" class="btn btn-primary">Add</button></td>
</tr>
{% endfor %}
</table>
</div>
</div>
<div class="container col-sm-6">
<table id='cart'>
</table>
<div id='pricefooter'>
<h1 style='margin-top:25px; border-top:.5px black solid;'>Subtotal: $<span id='subtotal'>0</span></h1>
<form action="{{url_for('Order')}}"><button type="submit" name="button" class='btn btn-warning'>Order</button></form>
</div>
</div>
</div>
{% endblock content %}
Cart Javascript pricecart.js
var tablerows = document.getElementById('table').rows.length;
var table = document.getElementById('table');
var cart = document.getElementById('cart');
var subtotal = document.getElementById('subtotal');
var username = document.getElementById('username').innerHTML;
var cartBadge = document.getElementById('cartbadge');
var pricesub = document.getElementById('pricefooter');
// On load cart
window.onload = function wowzers(){
var array = [];
var sum = 0;
// Get Data
var xhr = new XMLHttpRequest();
xhr.open('GET', 'pricing/orders/' + username +'/api', true);
xhr.onload = function(){
var data = JSON.parse(this.response);
cartBadge.innerHTML = data.length
if(xhr.status >= 200 && xhr.status < 400){
for(x in data){
for(key in data[x]){
array.push(Number(data[x][key]));
sum+=Number(data[x][key]);
subtotal.innerHTML = sum;
row = cart.insertRow(-1);
// Delete Data
row.addEventListener('click', function deleterow(){
index = this.rowIndex;
// subtotal.innerHTML = sum-Number(cart.rows[index].cells[1].innerHTML);
$.post('pricing/orders/delete', {
delete_item: index
});
cart.deleteRow(index);
});
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell3 = row.insertCell(2);
cell1.innerHTML = key;
cell2. innerHTML = data[x][key];
cell3. innerHTML = "<button class='btn btn-danger'>Delete</button>"
}
}
console.log(sum);
}else{
console.log(error)
}
}
xhr.send()
}
//Dynamic Cart
for(x = 0; x < tablerows; x++){
table.rows[x].addEventListener('click', addCartItem);
}
function addCartItem(ev){
var array = [];
var sum = 0;
index = this.rowIndex;
equipmentCell = table.rows[index].cells[0];
priceCell = table.rows[index].cells[1];
equipmentName = equipmentCell.innerHTML;
equipmentPrice = priceCell.innerHTML;
// Post Data
$.post('/pricing/orders/' + username + '/api', {
javascript_data: JSON.stringify({[equipmentName]:equipmentPrice})
});
cartrow = cart.insertRow(-1);
// Delete Data
cartrow.addEventListener('click', function deleterow(){
index = this.rowIndex;
// subtotal.innerHTML = sum-Number(cart.rows[index].cells[1].innerHTML);
$.post('pricing/orders/delete', {
delete_item: index
});
cart.deleteRow(index);
});
cell1 = cartrow.insertCell(0);
cell2 = cartrow.insertCell(1);
cell3 = cartrow.insertCell(2);
cell1.innerHTML= equipmentName;
cell2.innerHTML = equipmentPrice;
cell3.innerHTML = "<button class='btn btn-danger'>Delete</button>";
// Open Api information
var xhr = new XMLHttpRequest();
xhr.open('GET', 'pricing/orders/' + username +'/api', true);
xhr.onload = function(){
var data = JSON.parse(this.response);
cartBadge.innerHTML = data.length
if(xhr.status >= 200 && xhr.status < 400){
for(x in data){
for(y in data[x]){
array.push(Number(data[x][y]));
sum+=Number(data[x][y]);
subtotal.innerHTML = sum;
}
}
}else{
console.log(error);
}
}
xhr.send();
}
Flask Route routes.py
#app.route('/pricing/orders/<user_name>/api', methods=['POST', 'GET'])
#login_required
def api(user_name):
user_name = current_user.username
if request.method == 'POST':
cart.append(json.loads(request.form["javascript_data"]))
return jsonify(cart)
#app.route('/pricing/orders/delete', methods=['POST', 'GET'])
#login_required
def delete_item():
if request.method == 'POST':
print(cart[json.loads(request.form["delete_item"])])
cart.pop(json.loads(request.form["delete_item"]))
print(cart)
return jsonify({"whoa": "there"})
I'm a noob so this may be quite the long winded question an easy problem. Thanks guys!
You can try to bind event listener not to every single row (like you do in the loop), but for all of them in one time. After for loop add something like code below and remove event-listener in the loop, hope it will work:
document.querySelectorAll('.row-selector').on('click', function() {
... // do stuff with row
})
This problem can be solved using flask's context_processor. You can read more about it in official documentation. In a word you can put badge length in template's context and then use it anywhere in your templates, for example:
#app.context_processor
def inject_badge_length()
badge_length = ... // calculate badge length for current user
return {'BADGE_LENGTH': badge_length}
and then you can use it in template like:
<div class="badge-length">{{ BADGE_LENGTH }}</div>
Finally, if you have badge length (which can also be 0) you can hide subtotal html using css and javascript, like this:
#cart {
opacity: 0;
}
#cart.active {
opacity: 1;
}
and in js append this to the deleterow event-function (which, by the way, can be anonymous (nameless) function in this case):
if (cartBadge.innerHTML === "0") {
cart.classList.remove('active');
}
and somewhere in the end of 'addCartItem' function append:
if (!cart.classList.contains('active') && cartBadge.innerHTML !== "0") {
cart.classList.add('active');
}
I have a problem with the AngularJS two-way data binding. I'll try to explain the issue as clearly as possible: I have a list of contact names. For each element I have an Edit button. When I click on that button I load the "clicked" full Contact from an Ajax call and then I show a window with some input fields linked to the Contact just retrieved ("phone", "email" etc.). This is the interesting piece of the view:
<div>
<div class="contact" data-ng-repeat="contact in contacts">
<span>{{contact.label}}</span>
<a href="" class="btn btn-xs btn-default" data-ng-click="openContactModal(contact.ID)">
Edit
</a>
</div>
</div>
The click on the Edit button fires this function (present in the Controller):
var newContact = null;
$scope.openContactModal = function(contactID){
newContact = new Contact(contactID);
newContact.onLoad().then(
function(){
//loading OK
$('#myModal').modal('show');
},
function(){
//loading Error
}
);
$scope.newContact = newContact;
};
The call to new Contact(contactID) loads a contact from the Database with an Ajax call. I open the modal window at the end of the Ajax call (waiting for the AngularJS promise). In the modal, though, all fields are empty even though they are linked to the contact model (newContact.phone, newContact.email etc.). I've already checked that the Ajax call works fine (printing the resulted JSON). I suppose I'm missing something in the two-way data binding issue. The strange fact is that, if I try to fill the empty modal fields, the newContact model reacts well, as if the two-way data binding works well from the view to the model, but not the contrary. Thank you in advance!
EDIT: this is the service that retrieves the contact:
angular.module("app").factory("Contact", ["ContactDBServices", "$q",
function(ContactDBServices, $q){
return function(contactID){
//the contact itself
var self = this;
var contactPromise = $q.defer();
//attributi del contatto
this.firstName = null;
this.ID = null;
this.lastName = null;
this.phone = null;
this.fax = null;
this.mobile = null;
this.email = null;
this.web = null;
//the Ajax call
var metacontact = ContactDBServices.find({ID:contactID},
function(){
this.ID = contactID;
this.firstName = metacontact.contact_name;
this.lastName = metacontact.contact_last_name;
this.phone = metacontact.contact_phone;
this.fax = metacontact.contact_fax;
this.mobile = metacontact.contact_mobile;
this.email = metacontact.contact_email;
this.web = metacontact.contact_web;
//!!!THE FOLLOWING PRINTS ARE GOOD!!!!
console.log(this.ID);
console.log(this.firstName);
console.log(this.lastName);
console.log(this.phone);
console.log(this.fax);
contactPromise.resolve("OK");
},
function(){
contactPromise.reject("Error");
}
);
this.onLoad = function(){
return contactPromise.promise;
};
}
}]);
If I print the same values in the controller, though, all that values are undefined:
var newContact = null;
$scope.openContactModal = function(contactID){
newContact = new Contact(contactID);
newContact.onLoad().then(
function(){
//!!!!!!!!THE FOLLOWING PRINTS ARE ALL UNDEFINED!!!!
console.log(newContact.firstName);
console.log(newContact.lastName);
console.log(newContact.phone);
console.log(newContact.fax);
$('#myModal').modal('show');
},
function(){
//loading Error
}
);
$scope.newContact = newContact;
};
This is strange. It seems a sort of synchronization issue :-/ to be thorough here is an example piece of the modal:
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h2>Contact</h2>
</div>
<div class="modal-body">
<label>
Name
<input class="form-control" id="new_contact_name" data-ng-model="newContact.firstName" placeholder="Name">
</label>
<!-- ...and so on -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" data-ng-click="createContact()">Crea</button>
</div>
</div>
</div>
Eventually I found the mistake. It was a mistake of mine and it doesn't belong to AngularJS, but to Javascript: you'll note that, in the Contact service, I did:
//the Ajax call
var metacontact = ContactDBServices.find({ID:contactID},
function(){
this.ID = contactID;
this.firstName = metacontact.contact_name;
this.lastName = metacontact.contact_last_name;
this.phone = metacontact.contact_phone;
this.fax = metacontact.contact_fax;
this.mobile = metacontact.contact_mobile;
this.email = metacontact.contact_email;
this.web = metacontact.contact_web;
},
function(){
contactPromise.reject("Error");
}
);
clearly, writing this. in the callback function, I didn't affect the Contact values, but the function attributes! To solve this issue I had to change the callback this way:
//the Ajax call
var metacontact = ContactDBServices.find({ID:contactID},
function(){
self.ID = contactID;
self.firstName = metacontact.contact_name;
self.lastName = metacontact.contact_last_name;
self.phone = metacontact.contact_phone;
self.fax = metacontact.contact_fax;
self.mobile = metacontact.contact_mobile;
self.email = metacontact.contact_email;
self.web = metacontact.contact_web;
},
function(){
contactPromise.reject("Error");
}
);
where
var self = this;
outside the callback.