I am trying to create search bar(form), but I need it to have pretty URL but I am using Vue-router so my app.js looks like this
let Search = Vue.component('search', require('./components/Search.vue'));
const routes = [
{ path: '/protocols/:param', component: Search },
]
now functionally when I type /protocols/test I get my desired results, but I am not sure how to create a form so when I type something to redirect me to that route /protocols/:param since my page is vue component
<form action="/protocols/?what goes here?">
<input type="text" placeholder="Search..." class="" name="" id="search">
</form>
since all tutorials are made for search on the same page, but I need to dedicate one for results
You can use v-model to assign the input value to your data and use a computed property to generate the URL action like this:
<form :action="urlAction">
<input type="text" placeholder="Search..." class="" name="" id="search" v-model='search'>
</form>
Now use data and computed props to build the dynamic URL
data () {
return {
search: ''
}
},
computed: {
urlAction () {
return "/protocols/" + this.search
}
}
Related
I'm doing a CRUD with vue-cli and nodejs on the server side. So I have a form like this
<template>
<div id="formRoot">
<div class="form" >
<form #submit.prevent="sendToTable" action="/create" method="post">
Name
<input type="text" v-model="row.name" name="name" />
Price
<input type="number" name="price" v-model="row.price" />
Description
<textarea v-model="row.description" rows="3" name="desc"/>
<input type="submit" id="button" value="SAVE" />
</form>
</div>
<form class="" action="create" method="post">
<input type="text" name="input">
<input type="submit" value="send">
</form>
</div>
</template>
<script>
export default{
data(){
return{
row: {
name: '',
price: '',
description: ''
}
}
},
methods: {
sendToTable() {
console.log(this.row);
this.$parent.addToTable(this.row);
}
}
}
</script>
the #submit.prevent is for avoid the page refreshing and of course I have a method named sendToTable.
in node I have this:
const path = require('path');
const morgan = require('morgan');
const app = express();
//middlewares
app.use(express.urlencoded({extended: false}));
app.use(express.static(path.resolve(__dirname, '../dist')));
app.use(morgan());
app.post('/create', (req, res) => {
console.log(req.body);
});
const port = 3000;
app.listen(port, () => {
console.log('server listening on port ' + port);
});
the problem is that the server cant get the post request, I think is because the #prevent.default property.
I tried sending a post request with postman and it works, so I'm sure the problem is in the frontend.
What should i do? How are actually coded those single page web apps that can send data to the server?
You need to actually post your form data via an HTTP request. You can use a library like Axios (very popular) or fetch (check the supported browsers list).
Another thing you appear to be doing is calling a method on this component's parent. That goes against Vue's one-way data flow and isn't optimal. The better solution is to have your component emit an event with the attached data.
For example (using fetch)
<form #submit.prevent="sendToTable" method="post" action="/create">
methods: {
async sendToTable ($event) {
const form = $event.target
// post form as a regular "submit" would
let res = await fetch(form.action, {
method: form.method,
body: new URLSearchParams(new FormData(form))
})
if (res.ok) {
// emit the "row-added" event to the parent
this.$emit('row-added', { ...this.row }) // using spread syntax to break references
} else {
// you might want to do something else here in case of an error
console.error(res)
}
}
}
and in your parent component (assuming the child component is named RowAdder)
<RowAdder #row-added="addToTable"/>
I have setup a MVC webpage with a SlickGrid and can populate it upon initial page load. My javascript for loading:
$.getJSON("../Home/GetSlickGridData",
function(data) {
dataView.beginUpdate();
//dataView.setItems(data);
dataView.setItems(data, "OrderID");
dataView.setFilterArgs({
searchString: searchString,
searchShipmentID: searchShipmentID,
searchDestination: searchDestination,
searchCarrier: searchCarrier
});
dataView.setFilter(myFilter);
dataView.endUpdate();
});
This calls a controller action:
public JsonResult GetSlickGridData()
{
The issue now is that I'm unsure of how to refresh the grid when a search criteria is added to the cshtml page's search form:
#using (Html.BeginForm("GetSlickGridData", "Home"))
{
<table>
<tr>
<td>Shipper</td>
<td><input type="text" name="myText" id="txtShipper" /></td>
<td><input type="submit" value="Filter" onclick="GetData"></td>
</tr>
</table>
}
Can I use the loading for initial page load and for a search?
UPDATE:
Based on #Steve T's answer:
The search:
> <input type="text" name="myText" id="txtShipper" />
> <input type="button" value="Filter" onclick="GetData()">
The jquery:
function GetData() {
Slick.GlobalEditorLock.cancelCurrentEdit();
grid.invalidateAllRows();
var searchText = $("#txtShipper").val();
$.getJSON("../Home/GetSlickGridData?search=" + searchText,
function (data) {
The controller:
public JsonResult GetSlickGridData(string search)
And the map route (to ensure the controller works):
routes.MapRoute("search", "Home/GetSlickGridData/{search}",
new {Controller = "Home", Action = "GetSlickGridData"});
Instead of submitting the form and reloading the whole page you can change the filter button to type="button" and then use the GetData() function (not sure if you have this already implemented) to repeat the initial $.getJSON call with the value of text field txtShipper as a parameter
i want to search on the 'Index' and 'Type' that is input from the user through a html form. I'm new to both angular and Elasticsearch.
i tried using this code and binding the variables through ng-model
ExampleApp.controller('MatchController', function ($scope, client, esFactory) {
function click($scope){
$scope.index = '';
$scope.type = '';
$scope.key = '';
client.search({
index: $scope.index ,
type: $scope.type ,
size: 50,
body: {
"query":
{
"match": {
name: $scope.key
}
},
}
html code...
<input type="text" ng-model="index" id="index" /> <br><br>
<input type="text" ng-model="type" id="type" /><br><br>
<input type="text" ng-model="key" id="key" /><br><br>
<input type="button" value="search" onclick="click()">
Is it possible to do this??? if so how??
many thanks.
You need to create a service to connect and query elasticsearch using your functions.
https://www.sitepoint.com/building-recipe-search-site-angular-elasticsearch/
The above link shows you how to create and run queries via elasticsearch and AngularJS. The service that I mentioned is written in the last block of code. I suggest you read the whole article though to give you a better understanding.
You're mostly on the right track except your whole client.search part needs to go into a service which you call, otherwise whenever the controller is called that will be called too which you don't want happening.
I get duplicate ids when I set the views like so in my render function
var template = _.template($("#user-login-template").html(), {});
this.$el.html(template);
The html looks like this after running the render function, before runing the render function. Beforehand, the <div class ="app"> is empty (as it should be). It copy pasted the code from template and therefore the ids into the div.
<div class="app">
<input type="text" id="signup-username" placeholder="Username"/>
<input type="password" id="signup-password" placeholder="Create a Password"/>
<button id="signUpBtn">Sign Up</button>
<button id="logInBtn">Login</button>
</div>
<!-- Templates -->
<!-- Login Template -->
<script type="text/template" id="user-login-template">
<input type="text" id="signup-username" placeholder="Username"/>
<input type="password" id="signup-password" placeholder="Create a Password"/>
<button id="signUpBtn">Sign Up</button>
<button id="logInBtn">Login</button>
</script>
For reference, this is what my whole view looks like
var LogInView = Parse.View.extend({
el: '.app',
events: {
"click .signUpBtn": "signUp",
"click .logInBtn": "logIn"
},
initialize: function (){
this.render()
},
logIn: function () {
//To Do
},
render: function () {
var template = _.template($("#user-login-template").html(), {});
this.$el.html(template);
}
});
If Webstorm is complaining about the ids inside the <script> then it is wrong and you have three options:
Get a new IDE that has a better understanding of HTML.
Figure out how to reconfigure Webstorm to know what HTML really is. There must be a way to beat some sense into Webstorm, this sort of thing is very common these days.
Ignore the warnings (yuck).
Things inside <script> are not HTML and are not part of the DOM. Ask the browser what $('input[type=text]').length is after your template is rendered and you'll get 1 since the
<input type="text" id="signup-username" placeholder="Username"/>
inside the <script> isn't HTML, it is just text. You can even check the HTML specification of <script>:
Permitted contents
Non-replaceable character data
Non-replaceable character data is not HTML, it is just text.
I know that is posible with jquery but I dont know how to do that with angular js, please any sugestion?
function mayuscula(campo){
$(campo).keyup(function() {
$(this).val($(this).val().toUpperCase());
});
}
You can also create a directive for this!
Check the code:
directive('uppercase', function() {
return {
restrict: "A"
require: "?ngModel",
link: function(scope, element, attrs, ngModel) {
//This part of the code manipulates the model
ngModel.$parsers.push(function(input) {
return input ? input.toUpperCase() : "";
});
//This part of the code manipulates the viewvalue of the element
element.css("text-transform","uppercase");
}
};
})
For its usage, here's an example:
<input type="text" ng-model="myModel" uppercase />
You could do it in HTML template or via JS using the angular uppercase filter.
<div>
<label>Input 1</label>
<input type="text" ng-model="first">{{ first | uppercase }}
</div>
If you need to change the value in-place, use toUpperCase when ever value is changed.
<div>
<label>Input 1</label>
<input type="text" ng-model="first" ng-change="text = text.toUpperCase()">
</div>
Above in preferred approaches. Here's yet another way to achieve same result using $watch but this is not recommended. See comments section.
<div>
<label>Input 2</label>
<input type="text" ng-model="second">
</div>
var unwatch = $scope.$watch('second', function(val) {
$scope.second = $filter('uppercase')(val);
}, true);
$scope.$on('$destroy', unwatch);
Related Plunker here http://plnkr.co/edit/susiRn