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>
Related
In my form, there are 3 input values in the period line. If all of them are empty or zero, I want to give a warning in the kendo popup before clicking the button.If a non-zero value is entered for any of them, it will not give an error.
3 input values for period in form
My code is as below :
<form id="formPlan" onsubmit="return hasValue()" class="form-horizontal form-group-sm" data-toggle="validator">
<div class="form-group required">
<label for="inPeriod" class="control-label col-xs-3">#ln.label_period:</label>
<div class="col-xs-4 input">
<div class="row">
<div class="col-xs-4">
<input type="number" id="inPeriod_day" name="Period" class="form-control" max="365" step="any" maxlength="2" style="width:100%">
</div>
<div class="col-xs-4">
<input type="number" id="inPeriod_hour" name="PeriodHour" class="form-control" max="23" step="any" maxlength="2">
</div>
<div class="col-xs-4">
<input type="number" id="inPeriod_minute" name="PeriodMinute" class="form-control" max="59" step="any" maxlength="2">
</div>
</div>
</div>
</form>
<div id="popup">Periods can't be blank!</div>
<script>
$("#popup").kendoPopup({
animation: {
close: {
effects: "fadeOut zoom:out",
duration: 300
},
open: {
effects: "fadeIn zoom:in",
duration: 300
}
}
});
function hasValue() {
var period = document.forms["formPlan"]["Period"].value;
var periodhour = document.forms["formPlan"]["PeriodHour"].value;
var periodminute = document.forms["formPlan"]["PeriodMinute"].value;
if (!period && !periodhour && !periodminute) {
$("#popup").data("kendoPopup").open();
return false;
}
return true;
}
</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">';
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.
.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.
According to the docs of jQuery Validator doing this should programatically trigger form validation.
var validator = $( "#myform" ).validate();
validator.form();
But in my code it does nothing, why? I have a submit button on my form that is working fine, but validator.form() doesn't work at all. I've updated the post with my HTML form as well as the javascript code.
This is my form
<form class="kt-form kt-form--label-right" id="frm_sok" action="ajax/artikkel.php?a=sok_artikler" method="post">
<div class="kt-portlet__body">
<div class="kt-blog-post">
<div class="form-group ">
<div class="col-12">
<input class="form-control" type="search" value="{{ sok }}" id="searchinput" name="searchinput">
</div>
</div>
<div class="row">
<div class="col-4">
<label>Ikke søk i :</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="1" id="skjulnyheter" name="skjulnyheter">
<label class="form-check-label" for="skjulnyheter">Nyheter</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="1" id="skjulforum" name="skjulforum">
<label class="form-check-label" for="skjulforum">Forum</label>
</div>
</div>
<div class="col-4">
<label for="sorter">Sorter:</label><br />
<select class="form-control" name="sorter" id="sorter">
<option value="a.opp_dato DESC">Nyeste</option>
<option value="score">Beste treff</option>
<option value="a.opp_dato ASC">Eldste</option>
</select>
</div>
</div>
</div>
</div>
<div class="kt-portlet__foot">
<div class="kt-form__actions">
<input type="submit" class="btn btn-primary sokknapp" value="Søk" />
</div>
</div>
</form>
Here is my Javascript:
$( window ).on( 'load', function()
{
var validator = $("#frm_sok").validate(
{
rules:
{
searchinput:
{
required: true
}
},
messages:
{
searchinput :
{
required : 'Du må neste søke etter noe. Noe som helst. Ett eller annet.'
}
},
invalidHandler: function(event, validator)
{
$('.error').css( "display", "inline-block !important");
},
submitHandler: function(form)
{
preload_kamp();
$(form).ajaxSubmit(
{
success: function(data)
{
$( "#sokcontent" ).html(data);
}
});
}
});
validator.form();
});
I have an application built in Laravel 4 and uses this package
I am following this tutorial
This is the error I am getting http://postimg.org/image/c4qwjysgp/
My issue is $token is not correctly passing or the $token is empty.
I have already done a var_dump($token); die(); and get nothing but a white screen so not data is passing.
Here is the view
#extends('layouts.main')
#section('content')
<h1>Your Order</h1>
<h2>{{ $download->name }}</h2>
<p>£{{ ($download->price/100) }}</p>
<form action="" method="POST" id="payment-form" role="form">
<input type="hidden" name="did" value="{{ $download->id }}" />
<div class="payment-errors alert alert-danger" style="display:none;"></div>
<div class="form-group">
<label>
<span>Card Number</span>
<input type="text" size="20" data-stripe="number" class="form-control input-lg" />
</label>
</div>
<div class="form-group">
<label>
<span>CVC</span>
<input type="text" size="4" data-stripe="cvc" class="form-control input-lg" />
</label>
</div>
<div class="form-group">
<label>
<span>Expires</span>
</label>
<div class="row">
<div class="col-lg-1 col-md-1 col-sm-2 col-xs-3">
<input type="text" size="2" data-stripe="exp-month" class="input-lg" placeholder="MM" />
</div>
<div class="col-lg-1 col-md-1 col-sm-2 col-xs-3">
<input type="text" size="4" data-stripe="exp-year" class="input-lg" placeholder="YYYY" />
</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg">Submit Payment</button>
</div>
</form>
#stop
Here is the route
Route::post('/buy/{id}', function($id)
{
Stripe::setApiKey(Config::get('laravel-stripe::stripe.api_key'));
$download = Download::find($id);
//stripeToken is form name, injected into form by js
$token = Input::get('stripeToken');
//var_dump($token);
// Charge the card
try {
$charge = Stripe_Charge::create(array(
"amount" => $download->price,
"currency" => "gbp",
"card" => $token,
"description" => 'Order: ' . $download->name)
);
// If we get this far, we've charged the user successfully
Session::put('purchased_download_id', $download->id);
return Redirect::to('confirmed');
} catch(Stripe_CardError $e) {
// Payment failed
return Redirect::to('buy/'.$id)->with('message', 'Your payment has failed.');
}
});
Here is the js
$(function () {
console.log('setting up pay form');
$('#payment-form').submit(function(e) {
var $form = $(this);
$form.find('.payment-errors').hide();
$form.find('button').prop('disabled', true);
Stripe.createToken($form, stripeResponseHandler);
return false;
});
});
function stripeResponseHandler(status, response) {
var $form = $('#payment-form');
if (response.error) {
$form.find('.payment-errors').text(response.error.message).show();
$form.find('button').prop('disabled', false);
} else {
var token = response.id;
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
$form.get(0).submit();
}
}
Here is the stripe.php in package
<?php
return array(
'api_key' => 'sk_test_Izn8gXUKMzGxfMAbdylSTUGO',
'publishable_key' => 'pk_test_t84KN2uCFxZGCXXZAjAvplKG'
);
Seems like the Config::get might be wrong.
It would have to be written this way.
Stripe::setApiKey(Config::get('stripe.api_key'));
I figured out the problem. In the source for the external javascript file, the "/" was missing at the beginning of the relative path. That is why the javascript file for the homepage was rendering fine but the /buy page was not rendering the javascript file.