Push and Insert at a time in Vuejs and PHP - vue.js

I want to push the value in Array. It will show the value instantly. There is no need to refresh the whole page.
app.todoList.push(this.todo)
With this line I am doing that.
At the same time I want to insert this value to Database. Here is the problem. Differently they are working perfectly. But combined it is problem.
Here is the problem snipet.
Data:
todo: null,
todoList: []
Form to submit:
<form class="w-100" #submit="createTodo">
<div class="form-group w-100">
<input type="text" class="form-control w-100" placeholder="What needs to be done? " v-model="todo">
</div>
</form>
Todo Print:
<ul>
<li v-for="todo in todoList">
{{ todo.todo_title }}
</li>
</ul>
Method of inserting data into db:
createTodo(e) {
// Pushing dot only
app.todoList.push(this.todo)
let formData = new FormData();
formData.append('todo_title', this.todo)
axios({
method: 'POST',
url: 'api/todos.php',
data: formData
}).then(function(res){
}).catch(function(res){
console.log(res)
});
this.todo = null
e.preventDefault();
}
What can I do to do it perfectly.

For starters I would say that a more standard way of doing it is pushing the todo in the Axios promise callback. This way you could also include the ID that is created from the backend in the object.
It's not entirely clear what the issue is, if the issue is that you get the li but empty name, the problem is that when you're doing app.todoList.push(this.todo) you're printing the 'todo_title'. What you need to do is push it with the key app.todoList.push({ todo_title: this.todo }).

Related

Getting form data on submit?

When my form is submitted I wish to get an input value:
<input type="text" id="name">
I know I can use form input bindings to update the values to a variable, but how can I just do this on submit. I currently have:
<form v-on:submit.prevent="getFormValues">
But how can I get the value inside of the getFormValues method?
Also, side question, is there any benefit to doing it on submit rather than updating variable when user enters the data via binding?
The form submit action emits a submit event, which provides you with the event target, among other things.
The submit event's target is an HTMLFormElement, which has an elements property. See this MDN link for how to iterate over, or access specific elements by name or index.
If you add a name property to your input, you can access the field like this in your form submit handler:
<form #submit.prevent="getFormValues">
<input type="text" name="name">
</form>
new Vue({
el: '#app',
data: {
name: ''
},
methods: {
getFormValues (submitEvent) {
this.name = submitEvent.target.elements.name.value
}
}
}
As to why you'd want to do this: HTML forms already provide helpful logic like disabling the submit action when a form is not valid, which I prefer not to re-implement in Javascript. So, if I find myself generating a list of items that require a small amount of input before performing an action (like selecting the number of items you'd like to add to a cart), I can put a form in each item, use the native form validation, and then grab the value off of the target form coming in from the submit action.
You should use model binding, especially here as mentioned by Schlangguru in his response.
However, there are other techniques that you can use, like normal Javascript or references. But I really don't see why you would want to do that instead of model binding, it makes no sense to me:
<div id="app">
<form>
<input type="text" ref="my_input">
<button #click.prevent="getFormValues()">Get values</button>
</form>
Output: {{ output }}
</div>
As you see, I put ref="my_input" to get the input DOM element:
new Vue({
el: '#app',
data: {
output: ''
},
methods: {
getFormValues () {
this.output = this.$refs.my_input.value
}
}
})
I made a small jsFiddle if you want to try it out: https://jsfiddle.net/sh70oe4n/
But once again, my response is far from something you could call "good practice"
You have to define a model for your input.
<input type="text" id="name" v-model="name">
Then you you can access the value with
this.name inside your getFormValues method.
This is at least how they do it in the official TodoMVC example: https://v2.vuejs.org/v2/examples/todomvc.html (See v-model="newTodo" in HTML and addTodo() in JS)
Please see below for sample solution, I combined the use of v-model and "submitEvent" i.e. <input type="submit" value="Submit">. Used submitEvent to benefit from the built in form validation.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<form #submit.prevent="getFormValues">
<div class="form-group">
<input type="email" class="form-control form-control-user"
v-model="exampleInputEmail"
placeholder="Enter Email Address...">
</div>
<div class="form-group">
<input type="password" class="form-control"
v-model="exampleInputPassword" placeholder="Password"> </div>
<input type="submit" value="Submit">
</form>
</div>
<script>
const vm = new Vue({
el: '#app',
methods: {
getFormValues (submitEvent) {
alert("Email: "+this.exampleInputEmail+" "+"Password: "+this.exampleInputPassword);
}
}
});
</script>
</body>
</html>
The other answers suggest assembling your json POST body from input or model values, one by one. This is fine, but you also have the option of grabbing the whole FormData of your form and whopping it off to the server in one hit. The following working example uses Vue 3 with Axios, typescript, the composition API and setup, but the same trick will work anywhere.
I like this method because there's less handling. If you're old skool, you can specify the endpoint and the encoding type directly on the form tag.
You'll note that we grab the form from the submit event, so there's no ref, and no document.getElementById(), the horror.
I've left the console.log() there to show that you need the spread operator to see what's inside your FormData before you send it.
<template>
<form #submit.prevent="formOnSubmit">
<input type="file" name="aGrid" />
<input type="text" name="aMessage" />
<input type="submit" />
</form>
</template>
<script setup lang="ts">
import axiosClient from '../../stores/http-common';
const formOnSubmit = (event: SubmitEvent) => {
const formData = new FormData(event.target as HTMLFormElement);
console.log({...formData});
axiosClient.post(`api/my-endpoint`, formData, {
headers: {
"Content-Type": "multipart/form-data",
}
})
}
</script>

Dojo update only part of template

I have created a widget based template like,
<div class="content">
<div>
<!-- rest of content-->
</div>
<div class="col-md-6">
<div class="panel" data-dojo-attach-point="sysinfo">
<ul class="col-md-12 stats">
<li class="stat col-md-3 col-sm-3 col-xs-6">Host:</br> <span><b class="value">{{hname}}</b></span>
</li>
<li class="stat col-md-3 col-sm-3 col-xs-6"># CPU:</br> <span><b class="value">{{cpu}}</b></span>
</li>
</ul>
</div>
</div>
</div>
How do I update only content of sysinfo ?
Till now I was doing,
var widget = this;
widget.template = new dtl.Template(widget.templateString);
var template = widget.template;
template.update(node, stats); // but it update complete content as node == content. I just want to refresh sysinfo.
I also tried,
template.update(this.sysinfo, stats); // but it throws exceptions
Any ideas?
As far as I can see is that when you're using dojox/dtl/_Templated as suggested in the documentation, there is no update() function available.
If you really wish for certain things, you will have to manually define a template and render that one (and replace the attach point), for example:
var subtemplate = "<ul data-dojo-attach-point='sysinfo'>{% for item in list %}<li>{{item}}</li>{% endfor %}</ul>";
var template = "<div><h1>{{title}}</h1>" + subtemplate + "</div>";
var CustomList = declare("custom/List", [ _WidgetBase, _Templated, _DomTemplated ], {
templateString: template,
subTemplate: new dtl.Template(subtemplate),
title: "Fruits",
list: [ 'Apple', 'Banana', 'Lemon' ],
_setListAttr: function(list) {
this.list = list;
this.sysinfo = domConstruct.place(this.subTemplate.render(new dtl.Context(this)), this.sysinfo, "replace");
},
_getListAttr: function(list) {
return this.list;
}
});
Normally, if you would update the template when the list is set, you could use this.render() inside the _setListAttr() function to update the entire template.
However, as you can see in the _setListAttr() function I'm replacing an attach point by a newly rendered Django template.
This results in only that part of the template being updated, in stead of the entire template. So {{title}} would remain the original value, even when changed.
A full example can be found on JSFiddle: http://jsfiddle.net/pb3k3/

Knockout observable array

In my ViewModel for my MVC4 application I have some code to get names from an ajax call and populate a simple control within my page, which is using Bootstrap 3. As you can see below I have a hard-coded array which works perfectly. With the ajax call, I see the data in the UI but it does not update my control and I have NO idea why. I have verified the data exists and I have also tried setting self.Names = ko.observableArray within the ajax call. Is there a simple reason why? As I said I see the data within my form in both scenarios but I am not seeing the update I expect.
$(document).ready(function () {
function ViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Name = ko.observable("");
var Names = {
Name: self.Name
};
self.Name = ko.observable();
//self.Names = ko.observableArray([{ Name: "Brian" }, { Name: "Jesse" }, { Name: "James" }]);
self.Names = ko.observableArray(); // Contains the list of Names
// Initialize the view-model
$.ajax({
url: '#Url.Action("GetNames", "Home")',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
self.Names(data); //Put the response in ObservableArray
}
});
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
});
Here is the Response from the body via the ajax call:
[{"Id":1,"Name":"Brian"},{"Id":2,"Name":"Jesse"},{"Id":3,"Name":"James"}]
My HTML
<p>Current selection is <span data-bind="text:Name"></span></p>
<div class="container">
<div class="col-sm-7 well">
<form class="form-inline" action="#" method="get">
<div class="input-group col-sm-8">
<input class="form-control" placeholder="Work Section" name="q" type="text">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Select <span class="caret"></span></button>
<ul class="dropdown-menu" data-bind="foreach: Names">
<li class="dropdown">
</li>
</ul>
<input name="category" class="category" type="hidden">
</div>
</div>
Probably because the data coming in is either not structured the same as your bindings or observables are not set/updated properly. If they aren't observed then they wont update.
I'm not 100% sure on this, but I think you have to use the observable array functions in order for observers (UI elements bound to the array or its contents) to actually get updated. Basing this on a section from the observable array documentation on the knockout site:
2.For functions that modify the contents of the array, such as push and splice, KO’s methods automatically trigger the dependency tracking
mechanism so that all registered listeners are notified of the change,
and your UI is automatically updated.
Depending on the json, one way you might fix this is clear the observable array and reload it with data elements converted to observables:
self.Names.removeAll();
var newName = null;
for (var idx = 0; idx < data.length; idx++) {
newName = data[idx];
newName.Id = ko.observable(newName.Id);
newName.Name = ko.observable(newName.Name);
self.Names.push(newName);
}
On your html. the click function is using the Name property of the selected array element as the parameter. you don't want this, you want the latest value. So change this:
click: function() {$root.Name(Name);}
to this
//notice the new parenthesis after Name.
click: function() {$root.Name(Name());}

Pass Value of Drop Down as a Route Value to an Ajax Form

I am working on an ASP.NET MVC4 application, and I have the following in one of my views:
#using (Ajax.BeginForm("GetAllOrangeChocs", "ChocFactory", new { area = "Provider", Id = Model.FruitId }, new AjaxOptions { HttpMethod = "post", InsertionMode = InsertionMode.Replace, UpdateTargetId = "ChocFruitWrap" }, null))
{
<div class="form-horizontal" role="form">
<div class="form-group">
<span class="col-md-2 control-label"><strong>Fruit Group:</strong></span>
<div class="col-md-3">
#Html.DropDownListFor(m => m.FruitlId, new SelectList(Model.ListOf_Fruits,"Id", "PortalDisplayName"),"--Please Select--")
</div>
<div class="btn-group col-md-1">
<button type="submit" class="btn btn-primary btn-sm">Submit</button>
</div>
</div>
</div>
}
So it is an Ajax form that calls some controller action that returns a PartialView to display on the page. The controller code is:
public PartialViewResult GetAllOrangeChocs(int Id)
{
var model = _service.GetMeSomethingUsefulWithPassedParam(Id);
return PartialView("_Categories", model);
}
My controller action is being hit, but the Id is always null, my guess is, it is because there is no two way binding in place! As the ViewModel is passed in the GET Request, the FruitId on the ViewModel is null, and it only actually gets set in the POST
Am I right in my reasoning? And if yes ... how can I easily pass the Value (the Id) of the selected item in the Drop Down list?
I know I can added a hidden field, and via jQuery populate it each time the drop down changes, but is there no cleaner way?
from the link you have an ajax call
$.ajax({
type: "POST",
url: '#Url.Action("GetAllOrangeChocs", "ChocFactory")',
data: {
Selected: $('#FruitlId').val()
}
success: function (result) {
$('.divContent').html(result);
}
});
through the data attribute you can send whatever you want. What I have here will put the selected value into a variable called Selector (make sure whatever you call it on the view matches exactly with the input parameter on the controller). Let me know if you have any questions.

How to upload a file using AngularJs like the traditional way

I've been tried this for days. Assuming I have a form like following:
<form ng-submit="create()" class="form-horizontal" enctype="multipart/form-data">
<div class="control-group">
<label class="control-label">name : </label>
<div class="controls">
<input type="text" class="input-xlarge" ng-model="message.title" />
</div>
</div>
<div class="control-group">
<label class="control-label">avatar : </label>
<div class="controls">
<input type="file" ng-model="message.avatar" name="message[avatar]" />
</div>
</div>
<div class="well">
<input class="btn btn-large btn-primary" type="submit" value="建立資料" />
</div>
</form>
I am using the carrierwave gem to handle the file upload behind the scene. My controller is like this:
$scope.create = function($scope.message){
var deferred = $q.defer();
$http({
method: 'POST',
url: '/resources/messages',
data: $.param({message: message}),
headers: {'Content-Type': 'multipart/form-data'}
}).
success(function(data, status, headers, config){
deferred.resolve(data);
}).
error(function(data, status, headers, config){
deferred.reject(status);
});
return deferred.promise;
};
However it is not working. What I intend to do is create a form and upload everything like the old way, but the examples I found such as ng-upload, or like this post, or jquery file upload, they don't suit my need. Is there any example or sample code for this purpose? Thank you.
I think "like the old way" would be to not use Ajax, but I'm guessing that's not what you mean. :)
#shaunhusain's fiddle is a good example of how to use the FormData object to handle the file upload. And using this site as a reference, you can use the transformRequest to incorporate the FormData object.
Keeping your basic $http code, modify it to add the transform object:
$scope.create = function(message){
var deferred = $q.defer();
$http({
method: 'POST',
url: '/resources/messages',
data: message // your original form data,
transformRequest: formDataObject // this sends your data to the formDataObject provider that we are defining below.
headers: {'Content-Type': 'multipart/form-data'}
}).
success(function(data, status, headers, config){
deferred.resolve(data);
}).
error(function(data, status, headers, config){
deferred.reject(status);
});
return deferred.promise;
};
Create a factory that will incorporate manipulate the form data into a sendable payload. It will iterate through your form data (including uploaded file) and return a sender-friendly object:
app.factory('formDataObject', function() {
return function(data) {
var fd = new FormData();
angular.forEach(data, function(value, key) {
fd.append(key, value);
});
return fd;
};
});
I haven't tested this, but it should work out of the box.