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);
});
});
Related
So i have a project in Laravel, I have added filters, and it filters the products fine. However, when products are filterd my add to cart buttons become unresponsive. I figured after inspecting the rendered code in the browser that the JS was not loaded. However if i manually refresh the page (or refresh in the code with location.reload()) then it works. However I want to avoid manual refresh because then I would lose the colour class added to the button to show that its active filter.
Below is the code for my product file which loads the products in a for loop from the controller:
products.blade.php
<div class="container">
<!--Grid row-->
<div class="row">
#foreach ($products as $p)
<div class="col-lg-3">
<div class="container">
<form action="{{ route('cart.add', $p->id) }}" data-id="{{ $p->id }}" id="addtocart">
<div class="row">
<h5>{{ $p -> name }}</h5>
<button type="button" id="submit" class="button has-shadow is-danger submit is-small">
Add to Cart
</button>
</div>
</form>
</div>
</div>
#endforeach
</div>
<div class="container">
{{ $products ->appends($request->query()) -> links() }}
</div>
</div>
products_show.blade.php - Where the JS is and where the above file is loaded. The issue occurs after the $('body').on('click', '.btn-filter' is called.
#extends ('layouts.app')
#section ('content')
<div class="box text-right">
<div class="row">
<button type="button" name="filter[]" value="Jackets" id="filterJackets" class="button is-info btn-filter">Jackets</button>
<button type="button" name="filter[]" value="Hoodies" id="filterHoodies" class="button is-info btn-filter">Hoodies</button>
</div>
</div>
<section class="products">
#include('product.products')
</section>
#endsection
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$(document)
.ajaxStart(function () {
$("#modal").show();
})
.ajaxStop(function () {
$("#modal").hide();
});
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
// Pagination
$('body').on('click', '.pagination a', function(e) {
var url = $(this).attr('href');
$.ajax({
url : url
}).done(function (data) {
$('.products').html(data);
}).fail(function () {
alert('Products could not be loaded.');
});
window.history.pushState("", "", url);
});
// Add to cart
$(".submit").click(function (e) {
e.preventDefault();
var p_id = $(this).closest("form").data('id');
var product_id = $("#product_id").val();
var url = $(this).closest('form').attr('action');
$.ajax({
url:url,
method:'POST',
data:{
product_id:product_id
},
success:function(response){
console.log("added to cart success");
},
});
});
$('body').off('click', '.btn-filter', function(e) {
$(this).removeClass("is-success");
});
$(".btn-filter").hover(function(){
$(this).addClass("is-danger");
}, function(){
$(this).removeClass("is-danger");
});
var filters = [];
$('body').on('click', '.btn-filter', function(e) {
e.preventDefault();
$(this).toggleClass('is-success');
filters = []; // reset
$('button[name="filter[]"]').each(function()
{
if ($(this).hasClass("is-success")) {
filters.push($(this).val());
}
});
var url = '{{ route('products.type') }}'+'?filter[storage]='+filters
$.ajax({
url : url
}).done(function (data) {
$('.products').html(data);
}).fail(function () {
alert('Products could not be loaded.');
});
window.history.pushState("", "", url);
});
});
</script>
I am not sure if the php code matters because the problem here is the add to cart button JS is not being called, but here it is anyways:
public function filterByType(Request $request){
$products = QueryBuilder::for(Auth::user()->products())
->allowedFilters(['type'])->paginate()
->appends(request()->query());
// Check if request is from ajax
if ($request->ajax()) {
return view('product.products', ['products' => $products])->render();
}
return view('product.products_show', compact('products'));
}
Thanks.
So i found a hackway to do this, However is there a better solution or a way to fix my issue? And is what i did here bad?:
I added location.reload() to the end of the btn-filter on click which will reload the page since reloading the page fixes the issue for me.
I then added the code below to the top of the script:
var window_url = window.location.href;
var url_filter_params = window_url.substr(window_url.indexOf("=") + 1)
var filter_params_array = url_filter_params.split(',');
$('button[name="filter[]"]').each(function()
{
if ($.inArray($(this).val(), filter_params_array) >= 0){
$(this).addClass('is-success');
}
});
This basically gets the URL parses it to get the params, and then shows adds the is-warning class back to the button to make it appear as selected. The filters also work.
Before this gets marked as a duplicate, please note that I've found a solution, but it's not working for me.
I'm making a web app that allows a user to log in, do a search for a movie, and then select a movie from the search results to add it to a 'wish list' that's associated with that user. My only background in web development is a Udemy course that I just finished, and this is the first project I've worked on independentaly.
I've got an ejs file that renders the search page. Here's a snippet of that file:
<%- include("./partials/header.ejs") %>
<div class="container">
<h1 class="text-center"> Create new Request for <em><strong><%= currentUser.username %></strong></em> </h1>
<div class="row justify-content-center">
<div class="col-12 col-lg-4">
<input id="search_box" class="form-control" type="text" name="title" placeholder="Movie Title">
<button id="search_button" class="btn btn-primary btn-block">Search</a>
</div>
</div>
<div id="results" class="row">
<h3> Results... </h3>
<div class="card mb-3">
<div class="row no-gutters">
<div class="col-lg-4">
<img id="poster_0" class="card-img" src="#" alt="Card image cap">
</div>
<div class="col-lg-8">
<div class="card-body">
<h5 id="movie-title_0" class="card-title"><strong>Batman Begins</strong> - <em>1984</em></h5>
<p class="card-text"><strong>Description</strong>:
<span id="movie-description_0">
</span>
</p>
<p class="card-text"><strong>IMDB Rating</strong>:
<span id="movie-rating_0">
</span>
</p>
<a id="add_button_0" href="#" class="btn btn-primary">Add to Requests</a>
........
</div>
</div>
<script src="/javascripts/apikey.js"></script>
<script src="/javascripts/search.js" currentUserId=<%= currentUser._id %> currentUserName=<%= currentUser.username %>></script>
<%- include("./partials/footer.ejs") %>
In the included script at the bottonm, I create an array of movie objects based on what's returned by TMDB. Here's the code from the script:
let baseURL = 'https://api.themoviedb.org/3/';
let configData = null;
let baseImageUrl = null;
let movieData = [];
let currentUserId = document.currentScript.getAttribute("currentUserId");
let currentUserName = document.currentScript.getAttribute("currentUserName");
let getConfig = function() {
let url = ''.concat(baseURL, 'configuration?api_key=', API_KEY);
fetch(url)
.then((result) => {
return result.json();
})
.then((data) => {
baseImageUrl = data.images.secure_base_url + data.images.poster_sizes[3];
configData = data.images;
console.log('config:', data);
console.log('config fetched');
})
.catch((err) => {
alert(err);
});
}
let runSearch = function(keyword) {
let url = ''.concat(baseURL, 'search/movie?api_key=', API_KEY, '&query=', keyword);
console.log("Keyword is: " + keyword);
console.log(url);
fetch(url)
.then((result) => {
return result.json();
})
.then((data) => {
for (let i = 0; i < 3; ++i) {
movieData[i] = {
movie_id: data.results[i].id,
movie_title: data.results[i].title,
movie_release_date: data.results[i].release_date,
movie_description: data.results[i].overview,
movie_rating: data.results[i].vote_average
};
document.querySelector("#results").style.visibility = 'visible';
document.querySelector("#poster_" + i).src = baseImageUrl + data.results[i].poster_path;
document.querySelector("#movie-title_" + i).innerHTML = "<strong>" + data.results[i].title + "</strong> - <em>" + data.results[i].release_date + "</em>";
document.querySelector("#movie-description_" + i).textContent = data.results[i].overview;
document.querySelector("#movie-rating_" + i).textContent = data.results[i].vote_average;
}
console.log(JSON.stringify(movieData));
});
}
document.addEventListener('DOMContentLoaded', getConfig);
console.log("The current user is: " + currentUserName + " - Id:" + currentUserId);
document.querySelector("#search_button").addEventListener('click', (e) => {
runSearch(document.querySelector("#search_box").value);
});
=================> MOST RELAVENT BIT BELOW <===============
for (let i = 0; i < 3; ++i) {
document.querySelector("#add_button_" + i).addEventListener('click', (e) => {
console.log("TEST OUTPUT: " + JSON.stringify(movieData[i]));
var xhr = new XMLHttpRequest();
var postUrl = "/users/" + currentUserId + "/requests/new";
xhr.open("POST", postUrl, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(JSON.stringify(movieData[i]));
});
}
When the 'add to requests' button is clicked, what should happen is that the data in movieData[i] gets converted to a string, and sent as a post request to /users/id/requests/new. Here are my route definitions:
const express = require('express');
const router = express.Router();
const middleware = require("../middleware/auth.js");
const User = require("../models/user.js");
/* GET users listing. */
router.get('/', (req, res) => {
res.send('respond with a resource');
});
router.get('/id/requests', (req, res) => {
res.render('../views/requests', {title: "Profile - Groovie"});
});
router.get('/id/requests/new', (req, res) => {
res.render('../views/new', {title: "New Request - Groovie"})
})
router.post('/:id/requests/new', (req, res) => {
console.log(req.body);
User.findById(req.params.id, (err, user) => {
if (err) {
console.log(err);
} else {
user.requested_movies.push({
movie_id: req.body.movie_id,
movie_title: req.body.movie_title,
movie_release_date: req.body.movie_release_date,
movie_description: req.body.movie_description,
movie_rating: req.body.movie_rating
});
console.log("Added movie " + req.body.movie_title);
user.save();
}
});
});
module.exports = router;
So here we have our problem: All of the data that's getting pushed to the User object is blank. The console.log(req.body) is showing me that there is some kind of error in the way that the post request is getting parsed. Here's what's getting output:
{
`{"movie_id":320288,"movie_title":"Dark Phoenix","movie_release_date":"2019-06-05","movie_description":"The X-Men face their most formidable and powerful foe when one of their own, Jean Grey, starts to spiral out of control. During a rescue mission in outer space, Jean is nearly killed when she's hit by a mysterious cosmic force. Once she returns home, this force not only makes her infinitely more powerful, but far more unstable. The X-Men must now band together to save her soul and battle aliens that want to use Grey's new abilities to rule the galaxy.","movie_rating":6}`: ''
}
It took me forever to spot this, but I think that what's happening is that, instead of parsing each key-value pair as a key-value pair, the route is parsing the entire string as a single key, and the value is ''
Even if I take out the JSON.stringify bit from within the XMLHttpRequest.send() call and manually add a string like "number_of_dogs: 14, number_of_cats: 3", the same weird parsing takes place. The console.log from within the route definition prints out {"<whatever string was passed>" : ''}
I'm not married to the XmlHttpRequest method for getting the data to the new route, that's just the solution I found here. The course I took only really talked about making post requests via forms. Any guidance would be enormously appreciated.
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.
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();
}
I have list of divs with some data in there:
<div style="border: 1px solid #dddddd;">
<div id="wrap">
<h3 id="cText">#Model.CommentText</h3>
<a id="runEdit" href="#" >Edit</a>
</div>
</div>
When user click on runEdit link I make edit from this:
e.preventDefault();
var txt = $('#cText').text();
$('#cText').remove();
$('#wrap').prepend('<textarea>' + txt + '</textarea>');
$('#wrap').append('<input type="submit" value="Ok" />');
$('#wrap').append('<input type="submit" value="Cancel" />');
The problem is I added here this two buttons in javascript. But I don't know how to attach some controller action to this buttons?
The problem here is that if I write 5 comments. And click on edit I get 5 edit forms.
$('#editButton').live('click', function (e) {
e.preventDefault();
var container = $(this).closest('.commentWrap');
var itemId = container.attr('id');
var nestId = '#' + itemId;
var txt = $('#commentTextValue').text();
$(nestId + ' #commentTextValue').remove();
$(nestId + ' #editButton').remove();
$(nestId).prepend('<textarea id="editArea">' + txt + '</textarea>');
$(nestId).append('<input type="submit" value="Ok" class="btnOk" />');
})
$('.btnOk').live('click', function (e) {
e.preventDefault();
var container = $(this).closest('.commentWrap');
var itemId = container.attr('id');
var text = container.find('textarea').val();
var nestId = '#' + itemId;
//alert(nestId);
$.ajax({
url: '/Comment/SaveComment',
data: JSON.stringify({ CommentText: text, CommentId: itemId }),
type: 'post',
contentType: 'application/json',
success: function (data) {
if (data.success === true) {
//alert(data.message); // do show/hide stuff here instead of the alert
$(nestId + ' #editArea').remove();
$(nestId + ' .btnOk').remove();
$(nestId).append('<h3 id="commentTextValue">' + data.message + '</h3>');
$(nestId).append('<a id="editButton" href="#">Edit</a>');
}
}
});
});
</script>
<div style="border: 1px solid #dddddd;">
#Html.ActionLink(#Model.Author, "SomeAction")
<div class="commentWrap" id="#Model.CommentId">
<p id="commentTextValue">#Model.CommentText</p>
<a id="editButton" href="#">Edit</a>
</div>
</div>
First add an itemid to the div like this, and convert the id=wrap to a class, as there are more than one of them.
<div class="wrap" id="123"></div>
That way you get a way to reference the id of the item that you are editing.
You should also add a class to the submit button that you inject on the page, fx:
<input type="submit" class="btnOk" value="Ok"/>
Then you can hook up the javascript:
$('.btnOk').live('click',function(e){
e.preventDefault();
var container = $(this).closest('.wrap');
var itemId = container.attr('id');
var text = container.find('textarea')[0].val();
$.ajax({
url: '/mycontroller/savecomment',
data: JSON.stringify({comment: text, id:itemId}), // using JSON2, see below
type: 'post',
contentType: 'application/json',
success: function(data){
if(data.success===true){
alert(data.message); // do show/hide stuff here instead of the alert
}
}
});
});
NOTE: Download the json2 library and add it to you script references - it's a good way to do your json serialization. (https://github.com/douglascrockford/JSON-js)
In your controller you must add an action method to handle the request:
public ActionResult SaveComment(string text, int id)
{
//save your comment for the thing with that id
var result = new {success = true, message = "saved ok"};
return Json(result, JsonRequestBehavior.AllowGet);
}
The answer of Marc is collrect. Surround your code with this. However I strongly recommend you to make as much "html in html" rather than in JavaScript.
The above code could be translated to a better shape, like this,
<div style="border: 1px solid #dddddd;">
<div id="wrap">
<h3 id="cText">#Model.CommentText</h3>
<a id="runEdit" href="#" >Edit</a>
</div>
<div id="editPanel" style="display:none;">
<form action="#Url("Edit", "Whatevercontroller")">
<textarea name="CommentText">#CommentText</textarea>
<input type="submit" value="Ok" />
Cancel
</form>
</div>
</div>
and js would be
function StartEdit() {
$("#wrap").css("display", "none");
$("#editPanel").css("display", "block");
}
function CancelEdit() {
$("#wrap").css("display", "block");
$("#editPanel").css("display", "none");
}
the advantage of this approach that you do not generate too much DOM elements in this case. Otherwise chances tha your JavaScript will become absolutely unmanageable.
You have to put a form tag around your textarea and to set the action of the form by the #Url.Action helper to the needed action.
You need to make Ajax calls to your controller action. Please refer to below link :
http://tugberkugurlu.com/archive/working-with-jquery-ajax-api-on-asp-net-mvc-3-0-power-of-json-jquery-and-asp-net-mvc-partial-views
You will find a sample there.
Basically, what you need to do is as follows:
var d = "poo=1&bar=2";
$.ajax({
type: "POST",
url: "/home/myaction",
data: d,
success: function (r) {
alert(r.data);
},
complete: function () {
alert("I am done!");
},
error: function (req, status, error) {
//do what you need to do here if an error occurs
alert("error");
}
});