I have my back-end setup like this.
public function index()
{
$doc = Document::all();
return response()->json([
'Success' => [
'documents' => $doc->toArray()
],
], 200);
// return $doc;
}
In the front-end I have my factory class like this
query:
{
method:'GET',
isArray:false
},
and controller like this.
DocumentsFactory.query(function(documents) {
$scope.documents = documents;
});
Now this setup runs just fine. Here is my console.log
When I try the following in my html.
<div class="col-sm-5">
<select class="form-control m-b-sm" id="procedureId" ng-change="getSelectedProcedure(selectedProcedure.item)" ng-model="selectedProcedure.item" ng-options="document as (document.id + '-' + document.name) for document in documents" required="true"/>
<option value=" ">----------</option>
</select>
</div>
It does not work. Simply shows nothing in selection. Am I doing things the wrong way? What is the best practice for this kind of thing?
Related
For some reason, I can't quite figure out how to get an 'autocomplete' style multiselect with Vue working properly.
I properly set the route that is being called in my axios block, and the controller is set to use the query as a way to hit the database with a LIKE clause, but something is going wrong somewhere and my multiselect is not being filled with results from database that would make it searchable.
What am I doing wrong here?
Route:
Route::get('search', 'Controller#searchTags')
->name('search');
Controller:
public function searchTags(Request $request)
{
if ($request->get('query')) {
$query = $request->get('query');
$data = TAGS::where('TAG_DATA', 'LIKE', "%{$query}%")->get();
$output = '<ul class="dropdown-menu" style="display:block; position:relative">';
foreach ($data as $row) {
$output .= '<li>' . $row->tag_data . '</li>';
}
$output .= '</ul>';
return $output;
}
}
Blade:
<div id="tagContent">
<multiselect v-model="value" open-direction="bottom" :options="options" :multiple="true" :close-on-select="false" :taggable="true" :clear-on-select="false" :preserve-search="true" placeholder="Add Tag(s)" label="name" track-by="name">
<template slot="selection" slot-scope="{ values, search, isOpen }"><span class="multiselect__single" v-if="values.length && !isOpen">{{ values.length }} options selected</span></template>
</multiselect>
</div>
new Vue({
components: {
Multiselect: window.VueMultiselect.default
},
data () {
return {
value: [],
options: []
}
},
methods: {
read(){
window.axios.get('campaigns/search').then(({ data }) =>{
console.log(data)
});
},
addTag (newTag) {
const tag = {
name: newTag,
code: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000))
}
this.options.push(tag)
this.value.push(tag)
}
}
}).$mount('#tagContent');
There are a few things missing from your example, I believe.
You need to trigger the read function when the search input changes - use the #search-change event for that
You need to make use of the results of your axios request by sending them to this.options, so that the multiselect component can make use of them.
In this example, I've mocked the data request using a timeout, but you should get the idea. You can also make use of the loading property to let your users know something is happening behind the scenes.
I am new to js and would like to convert my JQuery-based js to Vue. I want to send a get request and output back the data. What is the best way of doing this?
Here is the html:
<div>
<div>
<input type="text" id="var1" placeholder="Search...">
</div>
<div>
<button id="submit">Submit</button>
</div>
</div>
<div>
<p>Results</p>
<p id="results"></p>
</div>
Below is my js:
$(document).read(function() {
$('#var1').keypress(function(e) {
if (e.keyCode == 13)
('#submit').click();
});
});
$(document).ready(function() {
$("#submit").click(function() {
var var1 = document.getElementById("var1").value
// sends get request to URL
$.getJSON("URL" + var1, function(search, status) {
console.log(search);
// cont.
$("#results").text(search.results);
});
});
});
EDIT: Here is what I have so far with axios:
function performGetRequest() {
var var1 = document.getElementById('var1').value;
axios.get('URL', {
params: {
id: var1
}
})
.then(function (response) {
console.log(search);
})
}
I am not sure if the above code is correct or how to factor in keypress and click-- is there a simple way to do that?
Well, I am not sure what you want to do with this ajax call, but hopefully this may help you. Vue is data driven, so I always try to focus on that aspect. So this is an example of how you can access and input and send the data using axios.
<div>
<div>
<input v-model='input' type="text" placeholder="Search...">
</div>
<div>
<button #click="searchInput()">Submit</button>
</div>
</div>
<div>
<p>Results</p>
<p >{{ result }}</p>
</div>
you must have those models in your data
// Your data
data() {
return {
input: '',
result: '',
}
}
and your method will look something like this.
searchInput() {
axios({
method: 'GET',
url: url + this.input,
}).then(response => {
this.result = response.data;
}).catch(error => {
//handle error
})
}
So this is a very basic example. you can do the same process in different ways, you could pass the input to the method or loop over the results, but the idea is taking advantage of Vue.js data driven system and think data first.
Hopefully this will help you, remember to escape your input and add necessary validations. Good luck
I have been following the Stripe integration tutorial by Laracasts and it's become apparent to me that a lot has changed since Laravel 5.4 was released. I have been able to still find my way along but I have hit a bump trying to submit a payment form using Vue and Axios.
The product is being retrieved from a database and displayed in a select dropdown - this works. My issue is the data is not being properly sent to the store function in the PurchasesController. When I try to make a purchase the form modal appears fine, I fill it out with the appropriate test data and submit it, but in Chrome inspector I can see that /purchases returns a 404 error and when I check the network tab the error is: No query results for model [App\Product]
Here is the original Vue code:
<template>
<form action="/purchases" method="POST">
<input type="hidden" name="stripeToken" v-model="stripeToken">
<input type="hidden" name="stripeEmail" v-model="stripeEmail">
<select name="product" v-model="product">
<option v-for="product in products" :value="product.id">
{{ product.name }} — ${{ product.price /100 }}
</option>
</select>
<button type="submit" #click.prevent="buy">Buy Book</button>
</form>
</template>
<script>
export default {
props: ['products'],
data() {
return {
stripeEmail: '',
stripeToken: '',
product: 1
};
},
created(){
this.stripe = StripeCheckout.configure({
key: Laravel.stripeKey,
image: "https://stripe.com/img/documentation/checkout/marketplace.png",
locale: "auto",
token: function(token){
axios.post('/purchases', {
stripeToken: token.id,
stripeEmail: token.email
})
.then(function (response) {
alert('Complete! Thanks for your payment!');
})
.catch(function (error) {
console.log(error);
});
}
});
},
methods: {
buy(){
let product = this.findProductById(this.product);
this.stripe.open({
name: product.name,
description: product.description,
zipCode: true,
amount: product.price
});
},
findProductById(id){
return this.products.find(product => product.id == id);
}
}
}
</script>
And my PurchasesController.
<?php
namespace App\Http\Controllers;
use Log;
use App\Product;
use Illuminate\Http\Request;
use Stripe\{Charge, Customer};
class PurchasesController extends Controller
{
public function store()
{
Log::info("Product Info: " . request('product'));
Log::info("Stripe Email: " . request('stripeEmail'));
Log::info("Stripe Token: " . request('stripeToken'));
$product = Product::findOrFail(request('product'));
$customer = Customer::create([
'email' => request('stripeEmail'),
'source' => request('stripeToken')
]);
Charge::create([
'customer' => $customer->id,
'amount' => $product->price,
'currency' => 'aud'
]);
return 'All done';
}
}
I realise that product isn't being passed through to /purchases above so I have tried this:
axios.post('/purchases', {
stripeToken: token.id,
stripeEmail: token.email,
product: this.product
})
Unfortunately I still get the same No query results for model [App\Product] error even with that. Is there another/better way of passing data from Vue/Axios that I could use instead? If anyone is able to assist it would be much appreciated.
Thank you in advance.
Edit
The solution was to recast this to be a new variable and it started functioning again. Here is the relevant portion of the Vue Code that worked for me:
created(){
let module = this; // cast to separate variable
this.stripe = StripeCheckout.configure({
key: Laravel.stripeKey,
image: "https://stripe.com/img/documentation/checkout/marketplace.png",
locale: "auto",
token: function(token){
axios.post('/purchases', {
stripeToken: token.id,
stripeEmail: token.email,
product: module.product
})
.then(function (response) {
alert('Complete! Thanks for your payment!');
})
.catch(function (error) {
console.log(error);
});
}
});
},
Are you sure when assigning the product ID to data (using product: this.product) that this keyword is really your Vue instance? You might need to bind it manually calling .bind(this) on the .post(...) call.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
I want to pass data from a simple HTML form to a controller through Ajax, then process the data and return a response back.
At the moment I have the following:
HomePage.ss
<form method="POST" class="form-horizontal submit-form" onsubmit="return checkform(this);">
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="name">Name</label>
<div class="col-md-8">
<input id="name" name="name" type="text" placeholder="insert full Name" class="form-control input-md" required="" />
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="send-btn"></label>
<div class="col-md-8">
<button id="send-btn" name="send-btn" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
JavaScript
$('form.submit-form').submit(function() {
$.ajax({
type: 'POST',
url: 'processForm',
data: $(this).serialize(),
success: function(data) {
alert('data received');
}
});
});
HomePage.php
class HomePage_Controller extends Page_Controller {
public function events() {
$events = CalendarEvent::get();
return $events;
}
public function processForm() {
if (Director::is_ajax()) {
echo 'ajax received';
} else {
//return $this->httpError(404);
return 'not ajax';
}
}
}
In developer tools I can see that I got the xhr processForm with a 404 not found error.
How do I get this Ajax form working correctly with the SilverStripe controller?
Spider,
I've done something similar to below. This is a quick and dirty demo and hasn't been tested, but it may get you going in the right path. If you're unfamiliar with how forms work within SilverStripe there is a lesson for front end forms in SilverStripe. I've found the lessons useful personally and provide the code for the lesson as well: http://www.silverstripe.org/learn/lessons/introduction-to-frontend-forms?ref=hub
Page.php
<?php
class Page extends SiteTree
{
}
class Page_Controller extends Content_Controller
{
private static $allowed_actions = array(
'MyForm',
);
public function MyForm()
{
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.min.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-validate/jquery.validate.min.js');
Requirements::javascript('/path/to/your/validation/script.js');
$fields = FieldList::create(
TextField::create('name')
->setTitle('Name')
);
$actions = FieldList::create(
FormAction::create('doSubmit')
->setTitle('Submit')
);
$requiredFields = RequiredFields::create(
'name'
);
$form = Form::create($this, 'MyForm', $fields, $actions, $requiredFields);
return $form;
}
public function doSubmit($data, $form)
{
//process $data or create your new object and simpley $form->saveInto($yourObject); then $yourObject->write()
//then deal with ajax stuff
if ($this->request->isAjax()) {
return $this->customise(array(
'YourTemplateVar' => 'Your Value'
))->renderWith('YourIncludeFile');
} else {
//this would be if it wasn't an ajax request, generally a redirect to success/failure page
}
}
}
YourValidationScript.js
(function ($) {
$(function () {
$('#MyForm_Form').validate({
submitHandler: function (form) {
$.ajax({
type: $(form).attr('method'),
url: $(form).attr('action') + "?isAjax=1",
data: $(form).serialize()
})
.done(function (response) {
$('.content').html(response);
})
.fail(function (xhr) {
alert('Error: ' + xhr.responseText);
});
},
rules: {
name: "required"
}
});
})
})(jQuery);
You need to understand how HTTP request routing is handled in SilverStripe.
When you send request POST /processForm, it is treated as page and managed by ModelAsController. That is why you get 404 error - there is no SiteTree record with URLSegment = processForm.
Solution 1
Use Form object. It creates all routing configuration automatically during runtime. Read more
https://docs.silverstripe.org/en/3.3/tutorials/forms/
https://docs.silverstripe.org/en/3.3/developer_guides/forms/
Solution 2
Use this approach, when you really want to go down to the simple one method request handler. Register custom controller and routing.
You specify your route in mysite/_config/routing.yml
---
Name: siteroutes
---
Director:
rules:
processCustomForm: CustomFormController
Handle your request
class CustomFormController extends Controller
{
public function handleRequest( SS_HTTPRequest $request, DataModel $model ) {
if (!$request->isPost()) {
// handle invalid request
}
$name = $request->postVar('name')
// process your form
}
}
I am using MEAN JS, i am trying to edit the list items on the list page, but it shows the error as below. i have initiated the data using ng-init="find()" for the list and ng-init="findOne()" for individual data.
Error: [$resource:badcfg] Error in resource configuration for action `get`. Expected response to contain an object but got an array
HTML
Below i the form inside the controller where it initiates the find() and findOne().
<div ng-controller="OrdersController" ng-init="find()">
<div>
<div class="order-filter">
<div ng-repeat="order in orders">
<form ng-init="findOne()" name="orderForm" class="form-horizontal" ng-submit="update(orderForm.$valid)" novalidate>
<input type="text" class="" ng-model="order.title">
<input type="text" class="" ng-model="order.content">
<div class="form-group">
<input type="submit" value="Update" class="btn btn-default">
</div>
</form>
</div>
</div>
</div>
</div>
Controller
$scope.update = function (isValid) {
$scope.error = null;
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'orderForm');
return false;
}
var order = $scope.order;
order.$update(function () {
$location.path('orders/' + order._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
$scope.find = function () {
Orders.query(function loadedOrders(orders) {
orders.forEach(appendFood);
$scope.orders = orders;
});
};
$scope.findOne = function () {
$scope.order = Orders.get({
orderId: $stateParams.orderId
});
};
You need to check your Orders Service which probably is using $resource to provide your API requests (Orders.query)
It should look something like this:
function OrdersService($resource) {
return $resource('api/orders/:orderId', {
orderId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
The style may be different depending on which version of mean you're using. By default, the $resource query will expect an array of results, but if for some reason you've set "isArray" to false then it will expect an object.
https://docs.angularjs.org/api/ngResource/service/$resource