I'm fetching comments from api. and I'm trying to edit a comment from the list.
When i click edit i show a text area inside the comment box and a button to save the comment . which is working nicely.
The problem is when i click edit the edit textarea gets applied to all comment boxes :|
<div>
<i class="fas fa-pen text-action text-success mr-3" #click="showComment(comment.id)" v-if="user == comment.user_id" v-b-tooltip.hover title="edit"></i>
<i class="fas fa-times-circle text-danger" v-b-tooltip.hover title="delete" v-if="!editing" v-show="user == comment.user_id"></i>
<i class="fa fa-times text-action text-danger mr-3" v-if="editing" #click="editing = false" v-b-tooltip.hover title="cancel editing"></i>
</div>
</div>
<div v-if="editing">
<textarea class="form-control" v-model="commentEdited" :id="comment.id" :placeholder="comment.body"></textarea>
<button class="btn btn-xs btn-success" #click="editComment(comment)">save</button>
</div>
The show comment method :
showComment(comment_id) {
console.log("clicked" + comment_id);
for (let i = 0; i < this.comments.length; i++) {
if (this.comments[i].id == comment_id) {
this.comment.body = this.comments[i].body;
this.comment.id = this.comments[i].id;
this.editing = true;
}
}
},
the editing is a boolen.
when i click edit it should only open the textarea for the current comment only . not all the comments :\
I really cant figure this out .Any help is appreciated .
Its because editing boolean is used by all of the components so when setting it to true, all comments show. You could change editing to a string property that is equal to the id of the comment being edited:
<div>
<i class="fas fa-pen text-action text-success mr-3" #click="showComment(comment.id)" v-if="user == comment.user_id" v-b-tooltip.hover title="edit"></i>
<i class="fas fa-times-circle text-danger" v-b-tooltip.hover title="delete" v-if="!editing" v-show="user == comment.user_id"></i>
<i class="fa fa-times text-action text-danger mr-3" v-if="editing" #click="editing = ''" v-b-tooltip.hover title="cancel editing"></i>
</div>
<div v-if="editing == comment.id">
</div>
showComment(id) {
this.editing = id
},
the reason is you are having editing as a common variable, i suggest you instead to carry a variable that holds the 'id'of your clicked comment, so
if you have something like
<div v-if="commentId===comment.id">
<textarea class="form-control" v-model="commentEdited" :id="comment.id" :placeholder="comment.body"></textarea>
<button class="btn btn-xs btn-success" #click="editComment(comment)">save</button>
</div>
where commentId is the variable into which you store the selected comment.id after that make it '' empty...
this would be my approach
Related
I have used Angular8 in my project, here if i have 2-3 records then Previous and Next works fine, but if i have more records, then when i click on previous/next, then it break the code and struck in the middle. Can anyone help, how to solve this issue. I have attached working demo of my code.
TS:
public changeDropdown(value) {
const entry = this.dropdownValue.findIndex(x => x.noteId === parseInt(value));
this.selectedDropdownValue = this.dropdownValue[entry].noteId;
}
public previousNextValue(value) {
let previousValue = this.selectedDropdownValue;
previousValue = value ? ++previousValue : --previousValue;
this.changeDropdown(previousValue);
}
HTML:
<div class="card-footer text-right">
<button class="btn btn-outline-primary" type="button" (click)="previousNextValue(false)"
[disabled]="selectedDropdownValue<=1"><i class="fas fa-chevron-left"></i>
Previous</button>
<button class="btn btn-outline-primary ml-1" type="button" (click)="previousNextValue(true)"
[disabled]="selectedDropdownValue==dropdownValue.length">Next <i class="fas fa-chevron-right"></i></button>
</div>
DEMO
You need to refactor your logic from value to index of array like
export class AppComponent {
selectedDropdownValue:number = 0;
selectedIndex: number = -1;
public dropdownValue = []; // data
public previousNextValue(selectedIndex) {
this.selectedIndex = selectedIndex;
this.selectedDropdownValue = this.dropdownValue[selectedIndex].noteId;
}
public changeDropdown(selectedDropdownValue){
this.selectedDropdownValue = selectedDropdownValue;
this.selectedIndex = this.dropdownValue.findIndex(x => x.noteId === parseInt(selectedDropdownValue));
}
}
And your view for next and previous will be like
<select class="custom-select w-100" name="noteTypeId" (change)="changeDropdown($event.target.value)" [value]="selectedDropdownValue">
<option value="0" selected disabled>Select Note Details</option>
<option *ngFor="let notesItem of dropdownValue" [value]="notesItem.noteId">
{{notesItem.dropdownSubject}}
</option>
</select>
<div class="card-footer text-right">
<button class="btn btn-outline-primary" type="button" (click)="previousNextValue(selectedIndex - 1)"
[disabled]="selectedIndex < 1"><i class="fas fa-chevron-left"></i>
Previous</button>
<button class="btn btn-outline-primary ml-1" type="button" (click)="previousNextValue(selectedIndex + 1)"
[disabled]="selectedIndex >= dropdownValue.length - 1">Next <i class="fas fa-chevron-right"></i></button>
</div>
DEMO
The problem is that you are looking for an ID that doesnt exist, and also you are using the same Variable for value and for The index, wich is causing troubles, you have to create another variable for setting the previousValue. Here's an example.
selectedDropdownValue:number = 0;
globalPreviousValue: number = 0;
public dropdownValue = [
{"noteId":1,"noteTypeId":1,"noteTypeName":null,"noteSubject":"subject -1","createdDate":"2020-08-07T15:21:48.71","createdBy":"Admin","noteText":null,"dropdownSubject":"08/07/2020 Admin subject -1"},{"noteId":2,"noteTypeId":2,"noteTypeName":null,"noteSubject":"subject -2 test","createdDate":"2020-08-07T15:25:38.553","createdBy":"Admin","noteText":null,"dropdownSubject":"08/07/2020 Admin subject -2 test"},{"noteId":3,"noteTypeId":2,"noteTypeName":null,"noteSubject":"subject -3 test","createdDate":"2020-08-11T11:26:36.007","createdBy":"Admin","noteText":null,"dropdownSubject":"08/11/2020 Admin subject -3 test"},{"noteId":10,"noteTypeId":3,"noteTypeName":null,"noteSubject":"test","createdDate":"2020-08-12T11:50:14.653","createdBy":"Admin","noteText":null,"dropdownSubject":"08/12/2020 Admin test"},{"noteId":11,"noteTypeId":5,"noteTypeName":null,"noteSubject":"tested","createdDate":"2020-08-12T14:36:43.41","createdBy":"Admin","noteText":null,"dropdownSubject":"08/12/2020 Admin tested"},
{"noteId":12,"noteTypeId":135,"noteTypeName":"Email sent to Agent","noteSubject":"test","createdDate":"2020-08-12T17:25:15.71","createdBy":"Admin","noteText":null,"dropdownSubject":"08/12/2020 Admin test"},
{"noteId":13,"noteTypeId":136,"noteTypeName":"Fax to Agent","noteSubject":"tested","createdDate":"2020-08-12T17:29:59.97","createdBy":"Admin","noteText":null,"dropdownSubject":"08/12/2020 Admin tested"}]
public changeDropdown(value) {
this.globalPreviousValue = value
this.selectedDropdownValue = this.dropdownValue[value].noteId;
}
public previousNextValue(value) {
let previousValue = this.globalPreviousValue;
previousValue = value ? ++previousValue : --previousValue;
this.changeDropdown(previousValue);
}
Also Change the Validation in your HTML in order work as desired.
<div class="card-footer text-right">
<button class="btn btn-outline-primary" type="button" (click)="previousNextValue(false)"
[disabled]="globalPreviousValue<=1"><i class="fas fa-chevron-left"></i>
Previous</button>
<button class="btn btn-outline-primary ml-1" type="button" (click)="previousNextValue(true)"
[disabled]="globalPreviousValue==dropdownValue.length-1">Next <i class="fas fa-chevron-right"></i></button>
</div>
Working Demo
I am using yajra datatables in laravel and I have the "revisar" button that shows a modal (as shown in the following image):
modal show
I want to fill this textarea with information from the "detail" field of the database that is obviously different for each item of the datatable, how would you do to obtain that data? I thought about getting it from the variable of the partials.actions which I can send from the controller of the datatable, but I can't get that variable in blade view.
my partials.actios view:
<a href="{{ route('tareas.createfrom', Hashids::encode($id)) }}" class="btn btn-sm btn-success">
<i class="fas fa-fw fa-plus"></i>
Tarea
</a>
<a href="{{ route('solicituds.show', Hashids::encode($id)) }}" class="btn btn-sm btn-info">
<i class="fas fa-fw fa-eye"></i>
Ver
</a>
<button type="button" data-id="{{ $id }}" data-toggle="modal" data-target="#RevisaSolicitudModal" class="btn btn-warning btn-sm revisar" id="getActualizaId">
<i class="fas fa-fw fa-check-circle"></i>
Revisar
</button>
<button type="button" data-id="{{ $id }}" data-toggle="modal" data-target="#DeleteProductModal" class="btn btn-danger btn-sm" id="getDeleteId">
<i class="fas fa-fw fa-trash"></i>
Eliminar
</button>
Maybe I can get the variable "$detail" in the modal using JS, I don't know
Check bootstrap documentation: https://getbootstrap.com/docs/4.4/components/modal/#varying-modal-content
<button type="button" data-id="{{ $id }}" data-toggle="modal" data-target="#RevisaSolicitudModal" class="btn btn-warning btn-sm revisar" id="getActualizaId">
<i class="fas fa-fw fa-check-circle"></i>
Revisar
</button>
...
<script>
$('#exampleModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var id = button.data('id') // Extract info from data-* attributes
...
})
</script>
My Approach which worked:
1.Controller:
return \Yajra\DataTables\DataTables::of($trxDatatables)
->addIndexColumn()
->addColumn('action', function($row){
$stEditRoute = route('admission.students.edit',$row->id);
$stShowRoute = route('admission.students.show',$row->id);
$btns = '<button class="btn btn-danger btn-xs
deleteModalTriggerBtn " id="deleteModalTriggerBtn"
data-catid='.$row->id.' data-toggle="modal"
data-target="#delete"><span class="glyphicon glyphicon-trash" title="Delete Center"/></button>';
return $btns;
})
->rawColumns(['action'])
->toJson();
Jquery:
$(document).ready(function () {
// used the following technique so that I can use the custom attribute (data-catid) value of the trigger button (id="delete") when delete ajax is called.
$(function() {
var stId = null;
function getCatId() {
$('#delete').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var id = button.data('catid'); // Extract info from data-* attributes
stId = id;
});
}
getCatId();
$('.modal-footer').on('click', '.delete', function(e) {
e.preventDefault();
var token = $("meta[name='csrf-token']").attr("content");
var reason = $("#reason option:selected").text();
var notice = $("#notice").val();
$.ajax({
type: 'DELETE',
url: 'http://yoursite.test/workplace/admission/students/'+stId,
data: {
'id': stId,
'reason': reason,
'notice': notice,
"_token": token,
},
success: function (data) {
// console.log(data);
// $('.item' + $('.id').text()).remove();
}
});
});
});
});
<div class="form-group">
<span class='btn btn-file btn-block btn-default'> <i class='pe pe-7s-video'> </i> Choose from Library
<input type='file' class='form-control' name='answer_video' accept='video/*' capture='camera' placeholder='Record' id='answer_video'></span>
</div>
How to change the value "Choose from Library" to "video selected" after choosing file through file input using javascript
On change event, check if the this.files are more than 0.
Demo
document.querySelector( "[name='answer_video']" ).addEventListener( "change", function(){
if ( this.files.length > 0 )
{
this.parentNode.querySelector(".videoLabel").innerHTML = "file selected";
}
else
{
this.parentNode.querySelector(".videoLabel").innerHTML = "Choose from Library";
}
});
<div class="form-group">
<span class='btn btn-file btn-block btn-default'> <i class='pe pe-7s-video'> </i> <span class="videoLabel">Choose from Library</span>
<input type='file' class='form-control' name='answer_video' accept='video/*' capture='camera' placeholder='Record' id='answer_video'></span>
</div>
You can use EventListener DOMContentLoaded and onchange do something
reference here
document.addEventListener('DOMContentLoaded',function() {
document.querySelector('[type="file"]').onchange=changeEventHandler;
},false);
function changeEventHandler(event) {
// You can use “this” to refer to the selected element.
document.getElementById('video_option').innerHTML = 'video selected';
}
<div class="form-group">
<span class='btn btn-file btn-block btn-default'> <i class='pe pe-7s-video'> </i><span id='video_option'> Choose from Library</span>
<input type='file' class='form-control' name='answer_video' accept='video/*' capture='camera' placeholder='Record' id='answer_video'></span>
</div>
you may take help with jquery, hope it will help you.
$("input[type='file'][name='answer_video']").change(function(){
var id = $(this).attr("id");
var thisVal = document.getElementById(id).files[0].name;
var nameBox = '<div class="fileContainer"><span class="docFileName">'+thisVal+'</span><span class="glyphicon glyphicon-remove" onclick=removeAttachment("'+id+'")>X</span></div>';
$(this).before(nameBox).hide();
});
function removeAttachment(id){
$("#"+id).val("").show();
$(".fileContainer").remove();
}
You only need to use the onchange function with your input.
function changeName(){
document.getElementById("change").innerHTML = "changeName"
}
<div class="form-group">
<span id="change" class='btn btn-file btn-block btn-default'> <i class='pe pe-7s-video'> </i> Choose from Library
</span>
<input type='file' class='form-control' name='answer_video' placeholder='Record' id='answer_video' onchange="changeName()">
</div>
I have the following html:
<label class="btn btn-sm btn-info" ng-model="radioModel" btn-radio="'title'"><i class="fa fa-check text-active"></i> Jobprofil</label>
<label class="btn btn-sm btn-success" ng-model="radioModel" btn-radio="'division'"><i class="fa fa-check text-active"></i> Afdelinger</label>
For this i have the following $scope variable:
$scope.radioModel = 'title';
And a listner for changes:
$scope.$watch('radioModel', function (newValue, oldValue) {
if(newValue == 'title'){
$scope.dataset = $scope.titleSet;
}
else if(newValue == 'division'){
$scope.dataset = $scope.divisionDataset;
}
}, true);
However whenever i click either of the elements the value does not change (or atleast the $watch is not being called)
So what am i doing wrong?
It seems everything is OK in your snippet, $watcher is working fine, check the plunker:
http://plnkr.co/edit/c4bwHh8acsQZ2Y7RxCU9?p=preview
I have a controller which gets a Model as parameter, but the Model has a collection of another Model. The other parameters can be simply sent using a Form but the inputfield of the model are dynamic so you can add them using javascript or jQuery.
So what I don't know is, how to make a collection of the models from the inputs using javascript and send them to the controller.
this is what I have in the View
<div>
<div class="row">
<div class="col-xs-4 col-sm-6 ">
<div class="dropdown volledigeLengte verplicht-ruimte">
<button class="form-control btn btn-default dropdown-toggle #dis" data-toggle="dropdown">
verplichte velden toevoegen<i class="glyphicon glyphicon-chevron-down"></i>
</button>
<ul class="dropdown-menu volledigeLengte">
<li>Text <i class="glyphicon glyphicon-plus "></i>
<li>Foto <i class="glyphicon glyphicon-plus "></i>
<li>Kaart <i class="glyphicon glyphicon-plus "></i>
<li>Video <i class="glyphicon glyphicon-plus "></i>
</ul>
</div>
<div class="marging-top-voor-fields extraRuimtesVerplicht">
</div>
</div>
<div class="col-xs-4 col-sm-6 ">
<div class="dropdown volledigeLengte niet-verplicht-ruimte">
<button class="form-control btn btn-default dropdown-toggle #dis" data-toggle="dropdown">
Niet verplichte velden toevoegen <i class="glyphicon glyphicon-chevron-down"></i>
</button>
<ul class="dropdown-menu volledigeLengte">
<li>Text <i class="glyphicon glyphicon-plus "></i>
<li>Foto <i class="glyphicon glyphicon-plus "></i>
<li>Kaart <i class="glyphicon glyphicon-plus "></i>
<li>Video <i class="glyphicon glyphicon-plus "></i>
</ul>
</div>
<div class="extraRuimtesNietVerplicht marging-top-voor-fields">
</div>
</div>
</div>
</div>
this is what my javascript looks like
(function ($) {
$(function () {
var aantalVerplicht = 0;
var aantalNietVerplicht = 0;
var matrix = [];
for (var i = 0; i < 9; i++) {
matrix[i] = [];
for (var j = 0; j < 9; j++) {
matrix[j] = new Array(9);
}
}
var extra;
var addRuimte = function (e, type) {
extra = null;
if ($(this).parents('div').hasClass("verplicht-ruimte")) {
extra = $(".extraRuimtesVerplicht");
}
if ($(this).parents('div').hasClass("niet-verplicht-ruimte")) {
extra = $(".extraRuimtesNietVerplicht");
}
if (extra != null) {
$(extra).append('<div id="maring-top-voor-fields"><input class="col-sm-10 form-control" placeholder="Geef de vraag" /><span class="input-group-btn remove_ruimte"><button class ="col-sm-2 form-control btn btn-danger "><i class="glyphicon glyphicon-minus"></i></button></span></div>');
}
};
var removeRuimte = function (e) {
e.preventDefault();
$(this).parent('div').remove();
i--;
};
$(document).on('click', '.text', addRuimte("text"));
$(document).on('click', '.foto', addRuimte("foto"));
$(document).on('click', '.kaart', addRuimte("kaart"));
$(document).on('click', '.video', addRuimte("video"));
$('.extraRuimtesVerplicht').on('click', '.remove_ruimte', removeRuimte);
$('.extraRuimtesNietVerplicht').on('click', '.remove_ruimte', removeRuimte);
});
})(jQuery);
this is what it looks like
I resolved a similar problem as follows.
Ensure that all IDs are unique
Use form tags
The following JavaScript then sends the form content to the server (I have generalised this to include to forms - the original worked with 10 forms).
function SaveAllAsIs() {
// save section 5 summaries first
var form_section11Data = JSON.stringify($("#form_section11").formParams());
var form_section11Data = JSON.stringify($("#form_section12").formParams());
$.ajax({
type: 'POST',
url: '/Area/DataSave/SaveAsIs',
data: JSON.stringify({
form_section11: form_section11Data,
form_section12: form_section12Data
}),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data.Success == "False") { alert("Error saving data, please try later"); }
}
});
}
The controller method looks like:
public JsonResult SaveAsIs(string form_section11, string form_section12)
{
SerializeModel(new JavaScriptSerializer().Deserialize<IDictionary<string, object>>
(form_section11, targetModel1);
SerializeModel(new JavaScriptSerializer().Deserialize<IDictionary<string, object>>
(form_section12, targetModel2);
}
And finally
public static void SerializePerinatalModel<T>(IDictionary<string, object> dataModel, T perinatalModel, int perinatalReportID)
{
Type sourceType = typeof(T);
foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
{
if (dataModel.ContainsKey(propInfo.Name))
I have only shown a partial function, but essentially each type is checked to see if it a list, and is so the list is then converted.
The other parameters can be simply sent using a Form but the inputfield of the model are dynamic so you can add them using javascript or jQuery.
Scott Hanselman has some details on passing arrays to MVC control binding: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
Which is essentially: ensure your controls have the correct names: using an index for lists
Although this doesn't directly address dynamic fields, it shows how it can be done.
replace:
$(extra).append('<div id="maring-top-voor-fields"><input class="col-sm-10 form-control" placeholder="Geef de vraag" /><span class="input-group-btn remove_ruimte"><button class ="col-sm-2 form-control btn btn-danger "><i class="glyphicon glyphicon-minus"></i></button></span></div>');
with:
var count = $("div#maring-top-voor-fields>input.col-sm-10.form-control").length;
$(extra).append(' ... <input name="answer["+ count + 1+"]" class="col-sm-10 form-control" placeholder="Geef de vraag" /> ... ');
One caveat: there cannot be any gaps in the numbers - so if you also dynamically remove any controls, then you'll have to change all the names to re-index them (which isn't very nice tbh).
With this, you can keep your controllers neat with IList<whatever> and have the framework bind them for you.
Alternatively, just use jquery!