I am using websocket to send images in a chat with spring boot and STOMP client with js - spring

Hello everyone I am using websocket to send images using stomp client and am facing this error:
Uncaught TypeError: Cannot read property 'files' of null
at sendMyImage (app.js:46)
at HTMLButtonElement.<anonymous> (app.js:68)
at HTMLButtonElement.dispatch (jquery.js:5201)
at HTMLButtonElement.q.handle (jquery.js:5009)
sendMyImage # app.js:46
(anonymous) # app.js:68
dispatch # jquery.js:5201
q.handle # jquery.js:5009
This is the code that am using in my index.html
<html>
<head>
<title>chat app</title>
<link href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/main.css" rel="stylesheet">
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
<script src="/app.js"></script>
</head>
<body>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="connect">WebSocket connection:</label>
<button id="connect" class="btn btn-default" type="submit">Connect</button>
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="participantId">ParticipantId :</label>
<input type="number" id="participantId" class="form-control" placeholder="Your id here...">
</div>
<div class="form-group">
<label for="id">Content :</label>
<input type="text" id="content" class="form-control" placeholder="Your message content here...">
</div>
<button id="send" class="btn btn-default" type="submit">Send</button>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label>Select an image and hit send:</label>
<input type="file" id="file" accept="image/*"/>
<button id="sendImage" class="btn btn-default" type="submit">Send Image</button>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="conversation" class="table table-striped">
<thead>
<tr>
<th>chatmessages</th>
</tr>
</thead>
<tbody id="chatmessages">
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
and this is my app.js code :
var stompClient = null;
const messageWindow = document.getElementById("messages");
const fileInput = document.getElementById("file");
const sendImageButton = document.getElementById("sendImage");
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#chatmessages").html("");
}
function connect() {
var socket = new SockJS('/ws');
socket.binaryType = "arraybuffer";//heere
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/chatmessages', function (chatmessage) {
showChatMessage(JSON.parse(chatmessage.body));
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendParticipantIdAndContent() {
stompClient.send("/app/chat", {}, JSON.stringify({'participantId': $("#participantId").val(),'content': $("#content").val()}));
}
function sendMyImage() {
let file = fileInput.files[0];
sendMessage(file);
fileInput.value = null;
}
function showChatMessage(message) {
$("#chatmessages").append("<tr><td>" + message.message + "</td></tr>");
}
function addImageToWindow(image) {
let url = URL.createObjectURL(new Blob([image]));
messageWindow.innerHTML += `<img src="${url}"/>`
}
$(function () {
$("form").on('submit', function (e) {
e.preventDefault();
});
$( "#connect" ).click(function() { connect(); });
$( "#disconnect" ).click(function() { disconnect(); });
$( "#send" ).click(function() { sendParticipantIdAndContent(); });
$( "#sendImage" ).click(function() { sendMyImage(); });
});
I really want to know what is the problem because i didn't get why he would be reading the file as a null.
Please tell me where did i mess up
and thank you

The problem is because the fileInput in your javascript is read as null.
you could try something like this
<input type="file" id="file" >
and access content like this
let file = document.getElementById("file").files[0];
And the problem here is definitely not related stomp or spring or websocket.

Related

Form won't submit after validation

I want to submit this form once its validate field, but it wont submit to the next page. I guess there something I need to add on jQuery.
Javascript:
(function() {
window.addEventListener('load', function() {
var forms = document.getElementsByClassName('needs-validation');
var validation = Array.prototype.filter.call(forms, function(form) {
form.addEventListener('submit', function(event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
//$(this).trigger('submit');
}
form.classList.add('was-validated');
}, false);
});
}, false);
})();
HTML:
<form class="needs-validation" action="save.php" method="post" id="form" name="form" novalidate>
<div class="row">
<div class="col">
<div class="mb-3">
<label class="form-label" for="exampleFormControlInput20">Info</label>
<textarea class="form-control" id="exampleFormControlTextarea25" rows="3" placeholder="Fill in your info"></textarea>
<div class="invalid-tooltip">Fill in this field.</div>
</div>
</div>
</div>
<div class="card-footer text-end">
<div class="col-sm-9 offset-sm-3">
<button class="btn btn-success active" type="submit" title="Submit Info">Submit</button>
<button class="btn btn-danger active" type="reset" title="Cancel">Cancel</button>
</div>
</div>
</form>
(function() {
window.addEventListener('load', function() {
var forms = document.getElementsByClassName('needs-validation');
var validation = Array.prototype.filter.call(forms, function(form) {
form.addEventListener('submit', function(event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
//$(this).trigger('submit');
}
form.classList.add('was-validated');
}, false);
});
}, false);
})();
<form class="needs-validation" action="save.php" method="post" id="form" name="form" novalidate>
<div class="row">
<div class="col">
<div class="mb-3">
<label class="form-label" for="exampleFormControlInput20">Info</label>
<textarea class="form-control" id="exampleFormControlTextarea25" rows="3" placeholder="Fill in your info" required minlength="10"></textarea>
<div class="invalid-tooltip">Fill in this field.</div>
</div>
</div>
</div>
<div class="card-footer text-end">
<div class="col-sm-9 offset-sm-3">
<button class="btn btn-success active" type="submit" title="Submit Info">Submit</button>
<button class="btn btn-danger active" type="reset" title="Cancel">Cancel</button>
</div>
</div>
</form>
When it passes validation you need to submit the form yourself.
if (form.checkValidity() === false)
{
event.preventDefault();
event.stopPropagation();
} else {
form.submit();
}

I'm new in ASP.NET CORE, and I'm trying to send data from dynamically created input fields to Controller

$("#addRow").click(function ()
{
#{
new VLSM_Model().LansValues.Add(new Lans());
}
var rowCount = parseInt($("#totalLans").val());
rowCount++;
$("#totalLans").val(rowCount);
var html = '';
html += '<div id="inputFormRow" style="width: 35%">';
html += '<div class="input-group mb-3">';
html += '<input type="number" id="[' + (rowCount - 1) + '].InitialLanValues" class="form-control m-input" placeholder="Enter number of Hosts" autocomplete="off" style="width: 30%" required>';
html += '<div class="input-group-append">';
html += '<button id="removeRow" type="button" class="btn btn-danger" style="margin-right: 5px">Remove Network</button>';
html += '</div>';
html += '</div>';
$('#newRow').append(html);
});
$(document).on('click', '#removeRow', function ()
{
var rowCount = parseInt($("#totalLans").val());
rowCount--;
$("#totalLans").val(rowCount);
$(this).closest('#inputFormRow').remove();
});
$(document).ready(function () {
$("#createButton").click(function ()
{
var inputData = $(this).serializeArray();
$.ajax(
{
type: "POST", //HTTP POST Method
url: "VLSM_Controller/Create", // Controller/View
data: inputData,
success : function(response) {
console.log(response)
}
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>VLSM CALCULATE</h1>
<hr />
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group" style="width: 35%">
<label asp-for="IP_Address" class="control-label"></label>
<input asp-for="IP_Address" class="form-control" />
<span asp-validation-for="IP_Address" class="text-danger"></span>
</div>
<br/>
<div class="form-group">
<div id="inputFormRow" style="width: 35%">
<div class="input-group mb-3">
<br/>
<div class="input-group-append"></div>
</div>
</div>
<div id="newRow">
<input type="hidden" id="totalLans" value="0" />
</div>
<button id="addRow" type="button" class="btn btn-info">Add Network</button>
</div>
<span asp-validation-for="LansValues" class="text-danger"></span>
<br/>
<div class="form-group" style="width: 35%">
<label asp-for="cidrValue" class="control-label"></label>
<input asp-for="cidrValue" class="form-control" />
<span asp-validation-for="cidrValue" class="text-danger"></span>
</div>
<br/>
<div class="form-group">
<input type="submit" value="Calculate VLSM" class="btn btn-info" id="createButton"/>
</div>
</form>
<div>
<a asp-action="VlsmResult">Back to List</a>
</div>
I created dynamically input fields as you can see from code, but I have difficulties to pass the data to controller, and to use the data for calculations inside the controller.
My question is how to pass data from dynamically created input fields with ajax to controller and how to use passed data for any kind of calculations.
Model binding system will look through the property by name. So you need match the name attribute in html with model property name. That is to say, your dynamic added input fields should have name attribute:name="LansValues[index].InitialLanValues".
Here is a whole working demo:
Model:
public class VLSM_Model
{
public string IP_Address { get; set; }
public List<Lans> LansValues { get; set; }
public int cidrValue { get; set; }
}
public class Lans
{
public int InitialLanValues { get; set; }
}
View:
Modify type="submit" to type="button", otherwise the ajax will not hit.
#model VLSM_Model
<h1>VLSM CALCULATE</h1>
<hr />
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group" style="width: 35%">
<label asp-for="IP_Address" class="control-label"></label>
<input asp-for="IP_Address" class="form-control" />
<span asp-validation-for="IP_Address" class="text-danger"></span>
</div>
<br />
<div class="form-group">
<div id="inputFormRow" style="width: 35%">
<div class="input-group mb-3">
<br />
<div class="input-group-append"></div>
</div>
</div>
<div id="newRow">
<input type="hidden" id="totalLans" value="0" />
</div>
<button id="addRow" type="button" class="btn btn-info">Add Network</button>
</div>
<span asp-validation-for="LansValues" class="text-danger"></span>
<br />
<div class="form-group" style="width: 35%">
<label asp-for="cidrValue" class="control-label"></label>
<input asp-for="cidrValue" class="form-control" />
<span asp-validation-for="cidrValue" class="text-danger"></span>
</div>
<br />
<div class="form-group">
#*change here*#
<input type="button" value="Calculate VLSM" class="btn btn-info" id="createButton" />
</div>
</form>
<div>
<a asp-action="VlsmResult">Back to List</a>
</div>
JS:
Change the dynamic html to name="LansValues[' + (rowCount - 1) + '].InitialLanValues" and change var inputData = $(this).serializeArray(); to var inputData = $('form').serializeArray();.
#section Scripts
{
<script>
$("#addRow").click(function ()
{
#*#{new VLSM_Model().LansValues.Add(new Lans());}*#
var rowCount = parseInt($("#totalLans").val());
rowCount++;
$("#totalLans").val(rowCount);
var html = '';
html += '<div id="inputFormRow" style="width: 35%">';
html += '<div class="input-group mb-3">';
//change id attribute to name attribute and modify the name
html += '<input type="number" name="LansValues[' + (rowCount - 1) + '].InitialLanValues" class="form-control m-input" placeholder="Enter number of Hosts" autocomplete="off" style="width: 30%" required>';
html += '<div class="input-group-append">';
html += '<button id="removeRow" type="button" class="btn btn-danger" style="margin-right: 5px">Remove Network</button>';
html += '</div>';
html += '</div>';
$('#newRow').append(html);
});
$(document).on('click', '#removeRow', function ()
{
var rowCount = parseInt($("#totalLans").val());
rowCount--;
$("#totalLans").val(rowCount);
$(this).closest('#inputFormRow').remove();
});
$(document).ready(function () {
$("#createButton").click(function ()
{
var inputData = $('form').serializeArray(); //change here...
$.ajax(
{
type: "POST", //HTTP POST Method
url: "Home/Create", // Controller/View
data: inputData,
success : function(response) {
console.log(response)
}
});
});
});
</script>
}
Controller:
public class HomeController : Controller
{
[HttpPost]
public IActionResult Create(VLSM_Model model)
{
//...
}
}
Note:
Actually if you just use form submit, it also can work well. If you use form submit, just change your original code:name="LansValues[' + (rowCount - 1) + '].InitialLanValues" in $("#addRow").click() function. Then remove the $("#createButton").click() function. No need change any other code.

Uncaught Error: You did not set a valid publishable key. Call Stripe.setPublishableKey() with your publishable key. all things are well config

.env file
STRIPE_KEY = pk_test_123...
STRIPE_SECRET = sk_test_123...
Stripe Form Code
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
$(function () {
var $form = $(".stripe-payment");
$('form.stripe-payment').bind('submit', function (e) {
var $form = $(".stripe-payment"),
inputVal = ['input[type=email]', 'input[type=password]',
'input[type=text]', 'input[type=file]',
'textarea'
].join(', '),
$inputs = $form.find('.required').find(inputVal),
$errorStatus = $form.find('div.error'),
valid = true;
$errorStatus.addClass('hide');
$('.has-error').removeClass('has-error');
$inputs.each(function (i, el) {
var $input = $(el);
if ($input.val() === '') {
$input.parent().addClass('has-error');
$errorStatus.removeClass('hide');
e.preventDefault();
}
});
if (!$form.data('cc-on-file')) {
e.preventDefault();
Stripe.setPublishableKey($form.data('stripe-publishable-key'));
Stripe.createToken({
number: $('.card-num').val(),
cvc: $('.card-cvc').val(),
exp_month: $('.card-expiry-month').val(),
exp_year: $('.card-expiry-year').val()
}, stripeRes);
}
});
function stripeRes(status, response) {
if (response.error) {
$('.error')
.removeClass('hide')
.find('.alert')
.text(response.error.message);
} else {
var token = response['id'];
$form.find('input[type=text]').empty();
$form.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
$form.get(0).submit();
}
}
});
</script>
<form role="form" action="{{ route('make-payment') }}" method="post" class="stripe-payment"
data-cc-on-file="false" data-stripe-publishable-key="{{ env('STRIPE_KEY') }}"
id="stripe-payment">
#csrf
<div class='form-row row'>
<div class='col-xs-12 form-group required'>
<label class='control-label'>Name on Card</label> <input class='form-control'
size='4' type='text'>
</div>
</div>
<div class='form-row row'>
<div class='col-xs-12 form-group card required'>
<label class='control-label'>Card Number</label> <input autocomplete='off'
class='form-control card-num' size='20' type='text'>
</div>
</div>
<div class='form-row row'>
<div class='col-xs-12 col-md-4 form-group cvc required'>
<label class='control-label'>CVC</label>
<input autocomplete='off' class='form-control card-cvc' placeholder='e.g 595'
size='4' type='text'>
</div>
<div class='col-xs-12 col-md-4 form-group expiration required'>
<label class='control-label'>Expiration Month</label> <input
class='form-control card-expiry-month' placeholder='MM' size='2' type='text'>
</div>
<div class='col-xs-12 col-md-4 form-group expiration required'>
<label class='control-label'>Expiration Year</label> <input
class='form-control card-expiry-year' placeholder='YYYY' size='4' type='text'>
</div>
</div>
<div class='form-row row'>
<div class='col-md-12 hide error form-group'>
<div class='alert-danger alert'>Fix the errors before you begin.</div>
</div>
</div>
<div class="row">
<button class="btn btn-success btn-lg btn-block" type="submit">Pay</button>
</div>
</form>
Error when submit the form
(index):3 Uncaught Error: You did not set a valid publishable key.
Call Stripe.setPublishableKey() with your publishable key. For more
info, see https://stripe.com/docs/stripe.js
at Function.b.validateKey ((index):3)
at Function.b.create ((index):2)
at Function.c.createToken ((index):2)
at HTMLFormElement. ((index):103)
at HTMLFormElement.dispatch (jquery-3.5.1.slim.min.js:2)
at HTMLFormElement.v.handle (jquery-3.5.1.slim.min.js:2)
Stripe.js should be initialized with your publishable key:
var stripe = Stripe('pk_test_123');
Additionally, you should not be collecting card details in your own form inputs, as it has PCI compliance implications. Instead, you should use Stripe Elements to securely collect this. Stripe's payment guide details how to implement this.

pass the value of a uploaded file photo in vuejs and Laravel

I want to upload my photo and pass the value to the laravel. I have this edit profile which my photo be uploaded. Now my problem is how will i able to pass the value of the photo to axios. Here is my code below
<template>
<div class="card">
<div class="card-header">Profile Form</div>
<div class="card-body">
<div class="container">
<div class="row">
<div class="col-sm">
<div v-show="updatePP" id="preview">
<img v-if="url" :src="url" />
</div>
<div v-show="pp" v-if="editProfile.profile_pic == NULL">
<img src="https://i.imgflip.com/4/d0tb7.jpg" />
</div>
<div v-else>
asasasas
</div>
</div>
<div class="col-sm">
<form #submit.prevent="formSubmit" enctype="multipart/form-data">
<div class="form-group">
<div class="form-row" >
<div class="col-lg-12">
<label>First Name:</label>
<br>
<input type="text" id="name" name="name" class="form-control" v-model="editProfile.name" />
</div>
<div class="col-lg-12">
<label>Last Name:</label>
<br>
<input type="text" id="lastName" name="lastName" class="form-control" v-model="editProfile.last_name" />
</div>
<div class="col-lg-12">
<label>Address:</label>
<br>
<input type="text" id="address" name="address" class="form-control" v-model="editProfile.address" />
</div>
<div class="col-lg-12">
<label>Upload Profile:</label>
<br>
<input type="file" id="photo" name="photo" #change="onFileChange" />
</div>
<div class="col-lg-12">
<br>
<br>
<button type="submit" class="btn btn-success btn-lg">Update</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return{
editProfile:{
userId: this.$userId,
},
url: null,
pp: true,
updatePP: false,
userId:this.$userId,
}
},
mounted(){
const url = window.location.href;
const id = url.split("/").slice(4)[0];
this.getEditProfile(id);
},
methods:{
onFileChange(e){
const file = e.target.files[0];
this.url = URL.createObjectURL(file);
this.editProfile.photo = file;
this.updatePP = true;
this.pp = false;
},
formSubmit(){
const ids = this.userId;
let currentObj = this;
alert(this.editProfile.name);
alert(this.editProfile.last_name);
alert(this.editProfile.address);
alert(this.editProfile.photo.name);
let formData = new FormData();
formData.append('photo', this.editProfile.photo.name);
formData.append('name', this.editProfile.name);
formData.append('lastName', this.editProfile.last_name);
formData.append('address', this.editProfile.address);
console.log(formData.values);
axios.put(`/api/profile/${ids}/update`, this.editProfile).then(response=>{
console.log(response.data);
currentObj.success = response.data.success;
}).catch(error=>{
console.log(error);
currentObj.output = error;
});
},
updateProfile(id){
},
getEditProfile(id){
axios.get(`/api/profile/${id}/edit`).then(response=>{
this.editProfile = response.data;
console.log(response.data);
});
}
}
}
</script>
<style scoped>
#preview {
display: flex;
justify-content: center;
align-items: center;
}
#preview img {
max-width: 250px;
max-height: 250px;
}
</style>
i am using the FormData() and i want the data to be pass to axios.
Any help is muchly appreciated. TIA
You need to include the file's input field and submit the FormData object you are creating.
Change your submit() function to something like this and HTML forms do not support PUT, PATCH or DELETE actions. So, when defining PUT, PATCH or DELETE routes that are called from an HTML form, you will need to sprrof it and add a hidden _method field to the form (https://laravel.com/docs/8.x/routing#form-method-spoofing):
formSubmit(){
const ids = this.userId;
let currentObj = this;
alert(this.editProfile.name);
alert(this.editProfile.last_name);
alert(this.editProfile.address);
alert(this.editProfile.photo.name);
let formData = new FormData();
formData.append('photo', this.editProfile.photo.name);
formData.append('name', this.editProfile.name);
formData.append('lastName', this.editProfile.last_name);
formData.append('address', this.editProfile.address);
formData.append('file', document.getElementById('fileInputId').files[0]);
console.log(formData.values);
axios.post(`/api/profile/${ids}/update`, formData).then(response=>{
console.log(response.data);
currentObj.success = response.data.success;
}).catch(error=>{
console.log(error);
currentObj.output = error;
});
},
Then to use put, add this to your form: <input type="hidden" name="_method" value="PUT">.
In your controller you can check to see if the file came through successfully with something like:
public function controllerMethod(Request $request)
{
if($request->hasFile('file')) {
dd('Success - there is a file.');
}
dd('Unsuccessful - there is no file');
}
This questions may help: How to send a file via Axios to Laravel

Angular Nested Comments - Values undefined when submitting form

I am trying to get a dynamic script for nested comments to work.
My first problem is that I don't know how I can do endless nesting. For now I planned to do 3 layers, cause I don't know how to make it work dynamicly.
The second problem is that when i submit the form, the values of the models is not submitted to the JS-script. The values are just undefined.
I guess my approach is just wrong - The ng-model elements are not bound inside of the ng-repeat, also the values of all forms would be bound to the same element... Maybe someone has some tips. If it is important, my backend runs with Laravel 4. Here is my code
var commentsApp = angular.module('commentsApp', []);
function CommentsCtrl($scope, $http, $compile) {
var url_segments = window.location.host.split('.');
var section = url_segments[0];
$http.get('/api/' + section + window.location.pathname + '/comments').success(function (comments) {
$scope.comments = comments;
});
$scope.toggleForm = function (id) {
var container = document.getElementById(id);
var html = '<br/><input name="category" type="text" ng-model="person.category" placeholder="Category" required/><span class="alert alert-error ng-show="add-bro.input.$error.required">Required</span>';
var elem = $compile(html)($scope);
angular.element(container).append(elem);
}
$scope.addComment = function () {
var comment = {
body: $scope.body,
commentable_id: $scope.commentable_id,
commentable_type: $scope.commentable_type
};
$scope.comments.push(comment);
};
}
commentsApp.controller('CommentsCtrl', CommentsCtrl);
<div class="content-row basic" ng-controller="CommentsCtrl" class="comments">
<form ng-submit="addComment()">
<input type="text" placeholder="Add Comment" ng-model="body">
<input type="hidden" value="#{{c.id}}" ng-model="commentable_id">
<input type="hidden" value="Player" ng-model="commentable_type">
<button type="submit">Add Comment</button>
</form>
<div ng-repeat="c in comments" class="comment">
<span>#{{c.author.username}}</span>
<p>#{{c.body}}</p>
<a href class="reply-link" ng-click="showForm = !showForm">Answer</a>
<div class="reply-container" ng-show="showForm">
<form ng-submit="addComment()">
<input type="text" placeholder="Add Comment" ng-model="body">
<input type="hidden" value="#{{c.id}}" ng-model="commentable_id">
<input type="hidden" value="Comment" ng-model="commentable_type">
<button type="submit">Add Comment</button>
</form>
</div>
<div ng-repeat="cc in c.comments" class="s-comment">
<span>#{{cc.author.username}}</span>
<p>#{{cc.body}}</p>
<a href class="reply-link" ng-click="showForm = !showForm">Answer</a>
<div class="reply-container" ng-show="showForm">
<form ng-submit="addComment()">
<input type="text" placeholder="Add Comment" ng-model="body">
<input type="hidden" value="#{{c.id}}" ng-model="commentable_id">
<input type="hidden" value="Comment" ng-model="commentable_type">
<button type="submit">Add Comment</button>
</form>
</div>
<div ng-repeat="ccc in cc.comments" class="ss-comment">
<span>#{{ccc.author.username}}</span>
<p>#{{ccc.body}}</p>
<a href class="reply-link" ng-click="showForm = !showForm">Answer</a>
<div class="reply-container" ng-show="showForm">
<form ng-submit="addComment()">
<input type="text" placeholder="Add Comment" ng-model="body">
<input type="hidden" value="#{{c.id}}" ng-model="commentable_id">
<input type="hidden" value="Comment" ng-model="commentable_type">
<button type="submit">Add Comment</button>
</form>
</div>
</div>
</div>
</div>
</div>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
//Comments object having reply oject
$scope.comments = [{ comment: 'hi', reply: [{ comment: 'hi inside commnet' }, { comment: 'hi inside commnet' }] }];
//push reply
$scope.insertReply = function (index, reply) {
$scope.comments[index].reply.push({ comment: reply });
}
//push commnet
$scope.newComment = function (comment) {
$scope.comments.push({ comment:comment, reply: [] });
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<!--Comment section-->
<ul ng-repeat="comment in comments track by $index" style="background: skyblue; padding: 10px;">
<li>
<b>Comment {{$index}} : </b>
<br>
{{comment.comment}}
<!--Reply section-->
<ul ng-repeat="reply in comment.reply track by $index">
<li><i>Reply {{$index}} :</i><br>
{{reply.comment}}</li>
</ul>
<!--End reply section-->
<input type="text" ng-model="reply" placeholder=" Write your reply." />Reply
</li>
</ul>
<!--End comment section -->
<!--Post your comment-->
<b>New comment</b>
<input type="text" placeholder="Your comment" ng-model="comment" />
Post
</div>

Resources