How can I pass a data-id value to a ViewComponent - asp.net-core-mvc

I want to use a ViewComponent in a Modal dialog to edit some data, I can get the ViewComponent to show on screen, when I click the button and if I hard code a value it will retrieve the correct data.
#await Component.InvokeAsync("Contact", 2);
or
#await Component.InvokeAsync("Contact", new { id=2 });
But what I can't see how to do is make the Id dependent upon which button I click. Ideally I'd like to just use data-id.
All the examples I've seen used fixed values.
Edit:
The ViewComponent is used in a ModalTagHelper, which is toggled on via an anchor tag, but I also have some jQuery that fires first.
$('.btnShow').on('click', function () {
$('#hdnContactId').val($(this).data('id'));
alert($('#hdnContactId').val());
});
Edit
<modal id="EditContact" title="Contact Details">
<modal-body>
#await Component.InvokeAsync("Contact", new { id=2 });
</modal-body>
<modal-footer>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</modal-footer>
</modal>

OK, so I finally figured a way to do it.
I removed the #await etc from the modal section, so by default it gets no data.
Then in the Controller I added:
public IActionResult ContactViewComponent(int Id) {
return ViewComponent("Contact", Id);
}
and changed my script to:
$('.btnShow').on('click', function (e) {
$('#hdnContactId').val($(this).data('id'));
var container = $(".modal-body");
$.get("/Contact/ContactViewComponent?Id=" + $(this).data('id'), function (data) { container.html(data); });
});
and it now works :)

Related

Browser-independent way to save text in a TextAreaFor

Using ASP.NET MVC, I have a View that contains a TextAreaFor, where I want users to be able to type in some notes and save them on-the-fly, see notes that were saved there before (whether by them or some other user), as well as modify existing notes (like to add additional notes). Here's what I have....
The divs in the View:
<div class="form-group">
<label for="InternalNotes" class="control-label">Internal Notes</label>
#Html.TextAreaFor(w => w.InternalNotes, new { #class = "form-control" , #id="notes" }) #*this is editable*#
</div>
<div class="form-group">
<div class="col-xs-6">
<button type="button" id="savenotes" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> Save Request Notes</button>
<div style="color:green; display:none" id="notessuccess">Notes successfully saved</div>
<div style="color:red; display:none" id="noteserror">Notes unable to be saved</div>
</div>
<div class="col-xs-6 text-right">
<button type="submit" id="deletereq" class="btn btn-default btn-primary" value="delete" name="submit"><span class="glyphicon glyphicon-remove"></span> Delete Request</button>
</div>
</div>
So the user could type something into the TextAreaFor, then hit the "savenotes" button, which should save them via Ajax. This is the jQuery for that:
$(document).ready(function () {
$("#savenotes").click(function () {
$("#notessuccess").hide();
$("#noteserror").hide();
var id = #Model.AccessRequestId;
var notes = document.getElementById("notes").textContent; //innerText;
$.ajax({
data: { 'id': id, 'notes': notes },
type: 'POST',
//contentType: "application/json; charset=utf-8",
url: '/Administration/SaveRequestNotes',
success: function (data) {
if (data.success == "ok") {
$("#notessuccess").fadeIn();
} else {
$("#noteserror").fadeIn();
}
},
fail: function (data) {
$("#noteserror").fadeIn();
}
});
});
});
The "innerText" is commented out because that's what I was originally using, but it was only working in Internet Explorer - another user is using Chrome, where he could see the other user's notes that were already there, but when he'd try to save notes in addition to theirs, it would blow it all out so the notes would be empty!
So I changed it to "textContent". That still works in Internet Explorer, but now in both Chrome and Firefox while it won't empty out existing notes, it still won't save new notes added. What is a browser-independent way I can make this work so everyone's notes will get properly saved whatever they are using?
Thank you!
You can use the jQuery val() method get the text user entered to the textarea
var notes = $("#notes").val();
alert(notes);
You might also consider using the Url.Action helper method to generate the correct relative path to your action method.
url: '#Url.Action("SaveRequestNotes","Administration")',

My function is deleting a different row to the one I intended, Laravel 5.4?

When I press remove, it removes the last charity in the database that belongs to the current user.
View (Button that deletes):
<a href="#"> <button class="btn btn-danger pull-right btnPopover" data-
toggle="popover" data-placement="top"> Remove </button> </a>
View (JS that is called):
function ConfirmDelete()
{
true;
}
$(document).ready(function()
{
$('.btnPopover').popover(
{
html: 'true',
title: '<strong> Are you sure you want to Remove? </strong>',
content: '<form style="display: inline;" action="{{
URL::to('remove', array($favourite->id)) }} "> <button class = "btn
btn-success glyphicon glyphicon-ok" onclick="return
ConfirmDelete()"> Yes </button> </form> <button class = "btn btn-
danger glyphicon glyphicon-remove"> No </button> '
});
$('.btnPopover').on('click', function (e)
{
$('.btnPopover').not(this).popover('hide');
});
Route:
Route::get('remove/{id}', 'HomeController#removeFavourite');
Controller (removeFavourite function):
public function removeFavourite($id)
{
Favourites::where('id', $id)->delete();
Session::flash('flash_message', 'Removed successfully!');
return back();
}
The strange thing is, is that I am using the exact same function and JS call in another part of the application and it is working fine!
The problem is, that it deletes the last record belonging to that user in the database.
Thanks
I don't know exactly what your code looks like, but the problem is that your JS is only valid for the last iteration of the loop, which sounds like what you're experiencing.
To fix it, you can move the form inside the popover button so that you can get the correct form link:
Example (moving the form):
<button class="btn btn-danger pull-right btnPopover" data-toggle="popover" data-placement="top" data-content='<form style="display: inline;" action="{{ URL::to('remove', array($favourite->id)) }} "> <button class = "btn btn-success glyphicon glyphicon-ok" onclick="return ConfirmDelete()"> Yes </button> </form> <button class = "btn btn-danger glyphicon glyphicon-remove"> No </button> '> Remove </button>
JS:
$(document).ready(function()
{
$('.btnPopover').popover(
{
html: 'true',
title: '<strong> Are you sure you want to Remove? </strong>',
});
$('.btnPopover').on('click', function (e)
{
$('.btnPopover').not(this).popover('hide');
});
....
This could be a little cleaner if you could access the parent button from the popover, but I couldn't find a way to do that in the API.
Check whether the $id you retrieve in your program(I assume there is some code missing in the question which finds the $id) is the one you want to delete.
Level official documentation says to use following code for deleting models:
$flight = App\Flight::find(1);
$flight->delete();
Find retrieves single model, and where returns a collection, so that might be the issue.
Also make sure that you pass the specific $id of the favourite that needs to be deleted, if not you'll always be deleting the last $id in your loop.
Official Docs

Using $state.go to call ui-router child state

So I am trying to have a sub menu that changes the state of the child view, and I am failing.
So set up the following function to call $state.go
$scope.stateGo = function (state) {
console.log("Loadting state " + state)
$state.go(state);
}
And I can see on the console that the correct (or what I think is the correct state name) is called
Loadting state board.stat
However, nothing at all seems to be happening with the actual router. If I change it so a parent state. It does work. For example, if I set it to board it works.
The files that contains the ui-views looks as follows:
<div ui-view="topmenu">
</div>
</div>
<div id="mainView">
<div ui-view="mainView">
</div>
<div style="height: 100px;"> </div>
</div>
<div class="col-md-offset-3 footer navbar-fixed-bottom" id="adView">
<div ui-view="adView">
</div>
</div>
The state config:
.state('board', {
url: "/view/board",
views: {
topmenu: {templateUrl: "views/partials/menu-board"},
mainView: {templateUrl: "views/partials/welcome"},
adView: {templateUrl: "views/partials/amazon-banner"}
},
//controller: 'testCtrl'
})
.state('board.stat', {
url: "/stat",
views: {
topmenu: {templateUrl: "views/partials/menu-board"},
mainView: {templateUrl: "views/partials/stat"},
adView: {templateUrl: "views/partials/amazon-banner"}
}
})
Am I missing something, should a call to $state.go('board.stat') get ui-router to load stat into mainView? And if so, any idea why it isn't?
======================= EDIT ===================
OK, think I might be doing it wrong, but not certain how...
Changed the buttons to use ui-href
<a ui-sref="board.stat" ui-sref-active="active" class="btn btn-xlarge" ><button class="btn btn-primary btn-circle btn-xl"><i class="fa fa-bar-chart fa-1x"></i><br><h6>Stats</h6></button></a>
<a ui-sref="board.quickbet" ui-sref-active="active" class="btn btn-xlarge" ><button class="btn btn-primary btn-circle btn-xl"><i class="fa fa-plus fa-1x"></i><br><h6>Quick bet</h6></button></a>
So same layout as earlier, but it seems like both child states are loaded ONLY when I enter parent state.
So I added some debugging for the state using the following two functions:
$rootScope.$on('$stateChangeError',
function(event, toState, toParams, fromState, fromParams, error){
console.log("State error: " + error);
})
$rootScope.$on('$viewContentLoading',
function(event, viewConfig){
// Access to all the view config properties.
// and one special property 'targetView'
// viewConfig.targetView
console.log("State event: " + viewConfig)
});
But the only output I get is:
2 State event: mainView#
2 State event: adView#
But when I press the buttons nothing seems to happen
Think I solved it.
Well, I did solve it, but I'm surprised by how it works.
So the problems seems to be that I thought the child state would reload the hole set of ui-views, it does not, and trying to do so seems to do nothing. I have no clue if this is correct interpretation, or expected behaviour, but this is what worked for me.
Load parent state with all three views (named topmenu, mainView and adView) (happens automatically).
Add a new ui-view (in my case in stats.ejs loaded on mainView)
This is your stats and bets
<ui-view></ui-view>
Last thing is to ONLY update the parts of the screen you wan't, so not mainView, but targeting the new ui-view in stats.ejs
.state('board.stat', {
templateUrl: "views/partials/stat"
})
And it works, just not certain if this has to do with the DOM or something, but it worked in my case

kendo ui - why do button click refresh the page?

Please find below my code:
Template of customer search form
<script type="text/x-kendoui-template" id="customer-search-view-template">
<div class="searchform" id="searchCustomer">
<form class="frmSearch">
<input name="searchTxt" data-bind="value: customerName" class="k-textbox" />
<button class="k-button" data-bind="click: searchClicked">Search</button>
<button class="k-button" data-bind="click: newClicked">New</button>
</form>
</div>
</script>
customer-search.js where loading above template and creating viewmodel object
$(function(){
var views = {};
templateLoader.loadExtTemplate("customer-search-view-template", "../views/customer-search-template.html");
var layout = new kendo.Layout($('#customer-search-view-template').html());
layout.render($("#main"));
// Create an observable view model object.
var customer = kendo.observable({
customerName: "John",
searchClicked: function() {
this.set("customerName", "Search clicked");
},
newClicked: function() {
this.set("customerName", "New clicked");
}
});
// Bind the view model to the personFields element.
kendo.bind($('#searchCustomer'), customer);
});
When I click the search button, the text is set in the textbox but this also refresh the page with ?searchTxt=Search+clicked in the address bar.
May I know why this button click refresh the page and how do I stop refreshing the page on button click ???
I would try and place the attribute 'type' for each like so:
<button type="button" class="k-button" data-bind="click: searchClicked">Search</button>
<button type="button" class="k-button" data-bind="click: newClicked">New</button>
The page thinks that each are performing a form submit action, but by placing the type attribute, you can access the event you intended for search. You may not need your form tags if you are not going to post any data, but rather just a js event handler. Good luck.
The reason is that you are inside a <form>, which has no settings (URL, method, etc), so the browser's default behavior is probably to perform a GET to the current URL (which is a refresh). You could just use <div> instead of <form> if you just want to execute that method.

Returning data from dynamic (AJAX) loaded Bootstrap Modal

I am using Bootstrap modal's in a Codeigniter application as a popup WYSIWYG text-editor. Everything in regards to loading content, and the modal, works fine. I can even save the content when the modal is open via AJAX.
But what I am trying to accomplish is when I hit the "Save" button in my modal... I want to return the value — $('#wysiwyg').val() — to the page that opened the modal.
Link triggering the modal
Write Text
JavaScript loading modal - Modified source from https://gist.github.com/drewjoh/1688900
$('.ajax-modal').click(function(e) {
e.preventDefault();
var modal = $('#ajax-modal');
var url = $(this).attr('href');
if(url.indexOf('#') == 0) {
$(url).modal('open');
} else {
$.get(url, function(data) {
modal.html(data);
modal.modal();
}).success(function() {
/* boom. loaded. */
});
}
});
HTML modal wrapper
<div id="ajax-modal" class="modal hide fade" data-backdrop="static" data-keyboard="false" tabindex="-1"></div>
HTML modal body/contents
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>Text Editor</h3>
</div>
<div class="modal-body">
<textarea class="input-block-level" id="wysiwyg" rows="9">Write something...</textarea>
</div>
<div class="modal-footer">
<button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button id="submit-modal" class="btn btn-success">Save</button>
</div>
Thanks in advance.
You could try something like this:
var modal = $('#ajax-modal');
// Filter clicks within the modal to those on the save button (#submit-modal)
modal.on('click', '#submit-modal', function(e) {
// Find the wysiwyg within the modal
var wysiwyg = $('#wysiwyg', modal);
// Now do what you want with wysiwyg.val();
if (wysiwyg.length) $('#my_info_div').html(wysiwyg.val());
});
I think I get what you are asking for...There are a few ways you can do this. If you want to create a more separated approach you could use a pub/sub framework like Amplify. The simplest approach would be to create a reference to the element you want to populate prior to creating the click event. Like so:
var controlToPopulate = $("#controlToPopulateId");
$('.ajax-modal').click(function(e) {
e.preventDefault();
var modal = $('#ajax-modal');
var url = $(this).attr('href');
if(url.indexOf('#') == 0) {
$(url).modal('open');
} else {
$.get(url, function(data) {
modal.html(data);
modal.modal();
}).success(function() {
/* boom. loaded. */
modal.find('#submit-modal').click(function() {
controlToPopulate.val(modal.find('#wysiwyg').val());
});
});
}
});
When you wrote if(url.indexOf('#') == 0), did you mean if(url.indexOf('#') == -1)? indexOf('#') returns -1 if # does not appear in the string.

Resources