I am in the middle of the development of a standalone widget in jQuery and RactiveJS template. Initially the widget is opened with dynamic input form elements and these elements are populated with AJAX call. Here the email is a static field. This is the initial view for the user. When a user clicks on a button in the widget, it will validate the form and send another AJAX-POST call with validated data and show the response of the request on a div inside the widget template itself. If the POST call fails, some error message should be displayed in the same div. I have successfully implemented the initial view of the widget and validation. Below is my code:
Template
<div> <!-- all the mustache {{}} variables are coming from the loadData() ajax call -->
{{#partial widget-header}}
<header>
<div >
<img alt="logo"><span>{{clientID}}</span>
</div>
</header>
{{/partial}} {{>widget-header}}
<section>
<div>
<div>
<form>
<span>Complete required fields </span> {{#partial mandatory}}
<em>*</em> {{/partial}}
{{#each items}}
<div>
<div>
<label>{{dynamicField}}</label>{{>mandatory}}</div>
<div>
<input type="text" name="{{dynamicField}}" maxlength="20">
<div>{{dynamicFieldHelp}}</div>
</div>
</div>
{{/each}}
<div >
<div>
<label>Your Email Id</label>{{>mandatory}}
</div>
<div >
<input type="text" name="email">
<div>enter your email</div>
</div>
</div>
<div >
<input type="button" value="Submit Form" on-click="formValidate">
</div>
</form>
</div>
</div>
</section>
</div>
JavaScript
this.ractive = new Ractive({
el: 'widgetContent',
template: mainTemplate,
data: function loadData() {
$.ajax({
async: false,
url: "https://example.com/xyz/" +employeeNo,
success: function (response) {
initialData = response.payload[0];
}
});
return initialData; // return the dynamic form elements in data field.
},
oncomplete: function () {
self.center();
}
});
this.ractive.on({
formValidate: function (ev) {
validate the form and send AJAX-POST call then display the response data in a div -
this is where I am stuck..
},
});
But the problem I am facing here in the second AJAX-POST call. I am not able to use a second data field in the ractive initialization. How can I implement this part ? If I use a second data field in the ractive, it will not call the first AJAX call for displaying the form elements. So my understanding is like only one data field can be added in the ractive initialization.
Do I need to use any advanced ractive concepts such as components to implement this part? Can someone help me on this.
note:- I haven't added divs for result handling in the template since I am stuck
You don't want two data members; what you want is for your data to contain a separate field for the response data. Based on what you have, data should initially be something like:
{
items: [],
response: 0
}
I would add an oninit function where you do the initial AJAX call, then when you get the response do ractive.set("items", items) to set it. Using set will cause Ractive to automatically update the view with your new items.
Next, in your formValidate function, make your AJAX call. When the response comes back, again use set to notify Ractive of the change: ractive.set("response", response). Add your div to the template:
{{#response}}
<div>{{response}}</div>
{{/}}
Related
I am developping a web app, using ASP .NET Core 2.0
I have a partial view that contains a form.
Then I have an action method inside a controller that is executed through a JS function, that uses AJAX.
This action method populates a model and returns the form partial view and corresponding model.
The function works well, as long as the model is not populated.
I need to fetch a record from the database when a determined field is filled and then loses focus. This works for the first time, when the model used in the form is empty. However, after finding a record for the first time and filling the form, the function is not executed anymore.
Also, the validations of the field also don't work after a record is loaded.
Here's the form partial view:
<form id="myform">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group col-lg-2">
<label asp-for="Client.Name">Client</label>
<input asp-for="Client.Name" id="ClientName" />
</div>
<div class="form-group col-lg-1">
<label asp-for="Cliente.Phone"></label>
<input asp-for="Cliente.Phone" id="Phone"/>
</div>
</form>
The JS/AJAX function:
<script>
$("form").on("blur", "#Phone", function () {
var phone = document.querySelector('#Phone').value;
alert('select client by phone=' + phone);
//Send the JSON array to Controller using AJAX.
$.ajax({
type: "POST",
url: "/Home/GetClienteByPhone",
data: "phone=" + phone,
success: function (res) {
$('#myform').html(res);
}
})
});
</script>
Finally, the controller action method (Controller=Home):
public IActionResult GetClienteByPhone(string phone)
{
if (!string.IsNullOrEmpty(phone))
{
var model = new FormViewModel();
model.Client = _db.Clients.Where(c => c.Phone == phone).FirstOrDefault();
return PartialView("_Form", model);
}
return PartialView("_Form");
}
On my View, I render the partial view into a div with id="myform"
Anyone knows why?
Thanks
It seems you're replacing your entire form in the AJAX callback. When you do that, you're also killing any attached event handlers. If you need the event handler to persist, you need to delegate it to a parent element that remains on the page after the replacement. You are using jQuery's delegate handler function, but your delegate itself is being replaced. You either need to not replace the entire form and just replace some child inside, or use a higher parent element than your form.
I have an angular form that is creating an object with tags:
<form class="form-horizontal" ng-submit="createBeacon(beaconData)">
<div class="form-group">
<label>Tags</label>
<div id="tags-list" data-current-user-company="{{current_user.company_id}}">
<input type="text" id="tags-input" class="form-control" ng-model="beaconData.tag_list" name="beacon[tag_list]" placeholder="project, client 72, yellow, design"/>
</div>
</div>
This form is submitting to a rails controller with a factory to commit to the database. Here is the function submitting the data:
$scope.createBeacon = function(beacon){
Beacon.save({
alias: beacon.alias,
description: beacon.description,
status: beacon.status,
company_id: currentUser.company_id,
venue_id: beacon.venue_id,
beacon_id: beacon.beacon_id,
tag_list: beacon.tag_list
});
}
The result is the tag_list being passed as a parameter to to Rails as seen in the server log below but it does not commit into the tags and taggings tables as it would if being submitted with a Rails form.
Any suggestions on what to do here?
Changing the strong parameters line from:
params.require(beacon).permit([:tag_list])
to:
params.permit([:tag_list])
fixed the issue of the tag_list not committing to the tags table. I know this is not preferable but it is the only solution I have found thus far.
"tag_list" => "Test 234" in your request shows it is passed in as a text not an array. You need to make it pass as an array.
Also you need to make sure permitted_params to permit tag list as an array.
params.require(beacon).permit(tag_list: [])
I have some modal with forms where I create object to store into database.
In these forms I have a Select field like this:
<div class="form-group" id=existingUser>
<label>Username</label> <select class="form-control select2"
style="width: 100%;" th:field="*{user}">
<option th:each="user: ${users}" th:value="${user.username}"
th:text="${user.username}"></option>
</select>
</div>
where users is passed from Controller with Model. With this approach I have to update all page to refresh the values inside select field otherwise I can only update the table where I show the new created object but I can't use the new field in select.
The problems are the performance and the look refreshing page, furthermore I can't use these instruction to show my message
location.reload();
//reload only the tag with id carsTable, so only the table
//$('#carsTable').load(document.URL + ' #carsTable');
$('#addCarModal').modal("hide");
notifyMessage("Your car has been created!", 'success');
function notifyMessage(textMessage, typeMessage){
$.bootstrapGrowl(textMessage, {
type: typeMessage, // (null, 'info', 'error', 'success')
});
}
Is there a way to call ajax when modal is called? Or can I pass data from javascript to HTML (if I retrive values when add button is clicked).
Sometimes I also check if select field are empty and in this case show a message inside the modals instead form.Thanks
UPDATE. I thouth this code:
To start with only success manage:
function freeUserController($scope) {
$http.get("https://localhost:8080/users/")
.success(function(data) {
$scope.users = data;
});
}
in my html page:
<div ng-controller="freeUserController" class="form-group" id=existingUser>
<label>Username</label> <select class="form-control select2"
style="width: 100%;" name="user">
<option ng-repeat="user in users" value="{{user.username}}">
{{user.username}}</option>
</select>
</div>
I assume you are rendering the HTML on the server. There is probably no way to make it re-render just that element. However, there are different ways you can do this:
One, you could start using client-side MVC / rendering like Angular.js. That way, you could automatically refresh the select field when a new field is added.
Two, you could put the new option into the select field without using an MVC system. That would require uncoupling the data from the view, so I wouldn't recommend it. However, you could have the submit button perform an ajax call to make sure the server reacted correctly, and only add the new option when the server response has arrived. Your code would look something like this:
$.ajax(url).done(function(){
$('#my-select').append('<option>').html('your data')
}).fail(function(){
// show error message...
});
I have to call $route.reload(); in controller 2 addData API call so that I can get the added data in my UI. But then the text 'Data added successfully' goes away due to page refresh.
controller 1:
$rootScope.$on('reloaded', function(event, data) {
$scope.$parent.alerts.length=0;
$scope.$parent.alerts.push({type: 'success',msg: 'Data added successfully'});
});
controller 2:
$scope.add = function() {
someAPIService.addData(JSON.stringify($scope.rows)).success(function(response) {
ngDialog.close('ngdialog1');
$route.reload();
$rootScope.$emit('reloaded', "true");
});
}
HTML Part:
<section>
<div ng-controller="controller3">
<alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</alert>
</div>
<div class="row form-inline" ng-controller="controller2 as vm">
<!-- Table data with text fields-->
</div>
<script type="text/ng-template" id="addDataDialog">
<div id="frm" ng-controller="controller1" class="col-xm-6">
<div class="form-group">
<!-- Labels with text fields-->
</div>
<button class="ngdialog-button" ng-click="add()">Save</button>
</div>
</script>
</section>
NOTE: Both controllers are in the same JS file and they are used for the same HTML file.
As you want to only load the latest record list which is on server side. Then there is not need to use $route.reload(); after making post call. You need to only make ajax call to get the latest records list that will solve your problem. For making ajax you need to refer $http
$route.reload() is getting used only when you need to load
controller again with specified template in your $routeProvider when
condition
just a simple hint of an answer:
add a (specific) cookie (with javascript) before calling reload (use e.g Cookies lib),
read it on reload,
and then delete it
Also you may use local storage if it is available instead of a cookie using same steps:
add a specific entry in local storage, before calling reload
read it on reload
and then delete it
Another option to maintain state client-side is to use url parameters but these will not do for page reload
I'm writing a small chat client/server app with KnockoutJS and Node.js, everything is good, except for the fact, that after I send a message, I lose focus on the message field, and users have to reclick it everytime they want to type (very annoying). Do you guys know what I can do? Here is the template:
<script type="text/html" id="chatRoom">
<div id="chatContainer" class="chatContainer">
<div class="chatFrom">
<i id="chatClose" class="chatSprite chatClose" data-bind='click: function() { server.removeChat(this) }'></i>
</div>
<div class="chatMessages">
<ul id="chatHolder">
{{each messages()}}
<li><div class="chatFromText">From: ${ from }</div>
<div class="chatTime">${ time }</div><div class="chatMsg">${ text }</div></li>
{{/each}}
</ul>
</div>
<div class="chatControls">
<form data-bind="submit: function() { send($('#'+channel).val()); $('#'+channel).focus(); }">
<input type="text" id="${ channel }" name="message" class="chatText" style="color: #999;" value="Message Here" data-bind='click: function() {
$("#"+channel).val("").css("color", "#000");
}' />
<i class="chatSprite chatSend" data-bind="click: function() { $('.chatSend').parent().submit() }"></i>
</form>
</div>
</div>
</script>
As you can see I have tried every possible way of focusing the field, but none seem to work. Any suggestions?
I think that your issue is likely that your "send" method does an asynchronous post back to the server, in the success callback it probably pushes the message to your messages observableArray. When this happens your template is re-rendered and your focus is lost. So, this happens after your $('#'+channel).focus() call, because the send completes asynchronously.
Can't be sure without seeing your send function.
One option would be to pass "channel" as another parameter to your "send" function, then in the success callback for your AJAX request after pushing the message to your messages observableArray set the focus based on channel.
Sample here: http://jsfiddle.net/rniemeyer/h2A6p/
Knockout now has a hasfocus binding.
Combining Aran's and Arun's answers, the easiest way that works for me is:
<input id="channel" type="text" data-bind="hasfocus: true" />
The reason is that your send function being asynchronous,
Either set async = false, if you are using ajax
Alternately,
you can use a view model property to hold a boolean value and use the hasfocus binding
function chatVM()
{
this.focus = ko.observable(true);
}
var vm = new chatVM();
And then inside your submit function
set vm.focus(true);
OR
set hasfocus of your message box to true always.
div class="msgbox" data-bind="hasfocus: ko.observable(true)"></div>