Action isn't call functions on view, from template - Ember - javascript

SO basically I create a view like so (I create it like this as I need it to act as a pop up)
Application.container = Ember.ContainerView.create();
Application.container.append();
Application.loginOverlay = Application.LoginOverlayView.create({
});
Application.childViews = Application.container.get('childViews');
Application.childViews.pushObject(Application.loginOverlay);
I have a view that looks like this
Application.LoginOverlayView = Ember.View.extend({
templateName: 'view/loginOverlay',
password: null,
logBackIn: function (password) {
console.log('logBackIn');
},
closeOverlay: function () {
console.log('closeOverlay');
},
username: function () {
return Application.user.get('username');
}.property().volatile()
});
Here's my template
<div id="login-overlay" class="overlay">
<section>
<form id="login_form">
<div class="control-group">
<label class="control-label" for="username">{{localise _username}}: {{username}}</label>
</div>
<div class="control-group">
<label class="control-label" for="reenter-password">{{localise _password}}</label>
<div class="controls">
{{view Ember.TextField name="reenter-password" elementId="reenter-password" valueBinding="password" placeholder="password" type="password"}}
</div>
</div>
<div class="control-group">
<input type="button" value="{{localise _login}}" class="btn btn-success" {{action 'logBackIn' password target="view"}} {{bindAttr disabled=busy}} />
<input type="button" value="{{localise _cancel}}" class="btn btn-danger" {{action 'closeOverlay' target="view"}} {{bindAttr disabled=busy}} />
</div>
</form>
</section>
</div>
The actions on the view are doing anything when clicked.
I'm using an old verion of Ember - v1.0.0-rc.7-9-g7398406
Any ideas?
*EDIT*
I did try it with the actions hash like so
Application.LoginOverlayView = Ember.View.extend({
// layoutName: 'view/loginOverlay',
templateName: 'view/loginOverlay',
password: null,
init: function () {
console.log('LoginOverlayView');
this._super();
},
actions: {
logBackIn: function (password) {
console.log('logBackIn');
},
closeOverlay: function () {
console.log('closeOverlay');
Application.removePasswordOverlay();
},
username: function () {
console.log('username');
return Application.user.get('username');
}.property().volatile()
}
});
but no joy. Also I added the init to make sure it was being created and it was, the log is being called
Another thing to add is that I'm not getting any feedback when I click the buttons. I'm not getting any kind of error or anything.

Related

vue3 v-model not work in js auto complete

I use javascript auto complete to finish the input text.
But I can't use v-model function of vue3 to get full value in my code.
Does any one can give me some advise, thanks.
<div class="row">
<div class="col-md-3">
<label for="fnode">fnode:</label>
<input type="text" class="form-control required" id="fnode" name="fnode" v-model="fnode">
</div>
<div class="col-md-3">
<label for="fnode">fnode:</label>
<button class="btn btn-primary form-control">{{ fnode }}</button>
</div>
</div>
<script>
Vue.createApp({
data: function(){
return {
fnode: '',
};
},
methods: {
},
mounted: function() {
},
}).mount('#form1');
</script>

Uncaught ReferenceError: Unable to process binding with KnockoutJS

We have a multiple page form like below , each page on the form is associated with different model classes. I am trying use the value the users selected in Page 1 and based upon that value selected in Pg1 I need to show/hide the field in Page2.
Page2 has a button which allows the users add courses, when they click on the button few fields shows up in the page in foreach loop and one of the field should show/hide based on the selection made on the previous page. But the above logic throws error like Uncaught ReferenceError: Unable to process binding "visible:" below is the viewmodel
How can I have the binding work properly here and get rid of the error
It's case sensitive. Also, the foreach loop changes the binding context, so you need to do this:
<div class="form-group required" data-bind="visible: $parent.Solution() == 'Other'">
Edit- that is, if you're indeed trying to reference the Solution property from the parent viewmodel. It's not clear from your example wheter a CoursesList item also has such a property.
Just expanding on #Brother Woodrow's answer with an very basic runnable example might help with things.
function ViewModel() {
var self = this;
self.pages = [1, 2]
self.currentPage = ko.observable(1)
self.solutions = ko.observableArray(['Solution 1', 'Solutions 2', 'Other']);
self.solution = ko.observable().extend({
required: {
params: true,
message: "Required"
}
});
self.next = function() {
self.currentPage(self.currentPage() + 1);
};
self.back = function() {
self.currentPage(self.currentPage() - 1);
};
self.CourseDetails = ko.observableArray();
self.addCourse = function() {
self.CourseDetails.push(new coursesList());
}
self.pageVisible = function(page) {
return self.currentPage() == page;
}
}
function coursesList() {
var self = this;
self.otherSolution = ko.observable().extend({
required: {
params: true,
message: "Required"
}
});
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div id="Page_1" data-bind="visible: pageVisible(1)">
<h2>Page 1</h2>
<div class="form-group required">
<label for="Solution" class="control-label">Solution</label>
<select id="Solution" name="Solution" class="form-control" data-bind="options: solutions, value: solution, optionsCaption: 'Select'"></select>
</div>
<button type="submit" id="NtPg" class="SubmitButton" data-bind="click: next">Next</button>
</div>
<div id="Page_2" data-bind="visible: pageVisible(2)">
<h2>Page 2</h2>
<button type="submit" id="AddCourseInfo" class="SubmitButton" data-bind="click: addCourse">Add Course Info</button>
<div data-bind="foreach:CourseDetails">
<div class="form-group required" data-bind="visible: $parent.solution() == 'Other'">
<label for="OtherSolution" class="control-label">Explain Other Solution : </label>
<input type="text" maxlength="1000" id="OtherSolution" name="OtherSolution" class="form-control" data-bind="value : otherSolution" required/>
</div>
</div>
<button type="submit" id="NtPg" class="SubmitButton" data-bind="click: back">Back</button>
</div>
<pre data-bind="text: ko.toJSON($root)"></pre>

Where/How to define a submit destination for my self created form (Vue) component?

I want to re-use a form component through my website, but the submit button will have to handle different things every time (display different data, depending which page is calling the form-component)
I'm a little bit new to paying around with Vue components and passing data between them, up until now I did messy one-page apps.
My current plan is have the form get the inputs/filters (from the form component), and when clicking submit, it should send this data (somehow?) to the element that called it - and will know how to handle it to the specific case from where it was called. I hope this is the right approach to this kind of scenario (?).
Is my plan a proper use of Vue / a proper way to submit a form from an external form-component?
In what way do I trigger the submit to send data / run a method outside of my DashboardForm.vue component?
How do I send fetched data of DashboardForm.vue component from ReportType1.vue and re-use this functionality in ReportType2.vue.
This is my Vue Form component (DashboardForm.vue):
<template>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<form id="mainForm" class="form-material row" method="POST">
<div class="" id="date-range">
<datepicker v-model="startDate" input-class="form-control inputDate" placeholder="Start Date" required></datepicker>
<div class="input-group-append">
<span class="input-group-text b-0 text-white"> to </span>
</div>
<datepicker v-model="endDate" input-class="form-control inputDate" placeholder="End Date" required></datepicker>
<input type="button" class="btn btn-info waves-effect waves-light" v-on:click="groupFilterDisplay(true);" value="Filter by Group"/>
<!-- <input type="button" id="submit-btn" class="btn btn-success waves-effect waves-light" v-on:click="loadNew" value="Submit"/> -->
<input type="button" id="submit-btn" class="btn btn-success waves-effect waves-light" value="Submit"/>
</div>
</form>
</div>
</div>
</div>
<transition name="fade">
<div id="groupFilter" class="popupGroupFilter" v-if="groupFilter">
<div id="filterArea">
<input type="text" v-model="searchGroupInput" placeholder="Search" class="gfSearch">
<span class="gfTitle">Filter by Group</span>
<hr>
</div>
<div class="ulTree">
<ul>
<tree_item class="item" v-bind:model="groupTree"></tree_item>
</ul>
</div>
<div v-on:click="applyGroupFilter();" class="gfClose gfApply"><span>✔ Apply</span></div>
<div v-on:click="groupFilterDisplay(false);" class="gfClose"><span>X Close</span></div>
</div>
</transition>
</div>
</template>
<script>
// import { GF } from '../mixins/GF.js';
export default {
name: 'DashboardForm',
// mixins: [GF],
data() {
return {
groupTree: window.groups,
searchGroupInput: '',
searchGroupArray: [],
groupFilterApplied: false,
groupFilterBackup: [],
selectedIds: [],
groupFilter: false,
startDate: null,
endDate: null,
mode: 0,
}
},
props: {
options: Array
},
watch: {
'searchGroupInput': function (newVal, oldVal) {
this.groupTree = this.searchGroupResult();
}
},
methods: {
recurseGroups: function (arr, action) {
},
applyGroupFilter: function () {
},
groupFilterDisplay: function (display) {
},
searchGroupResult: function () {
},
fetchGroupIds: function () {
}
}
};
</script>
This is the component that uses the DashboardForm for example (
ReportType1.vue):
<script>
import DashboardForm from "../tools/DashboardForm.vue";
export default {
components: {
DashboardForm
},
data() {
return {
};
},
created() {
},
mounted() {
},
destroyed() {
},
watch: {
},
methods: {
}
}
</script>
<!-- Template -->
<template>
<div>
<!-- Form -->
<DashboardForm/>
<!-- form result -->
<div id="resultContainer"> <datatable/> </div>
</div>
</template>
Okay if I understood you well, we are trying to build a reusable form component.
I will give you a quick overview of how VUE components communicate.
The component takes its necessary inputs using the props.
The component inner HTML can be passed from its user by using slot.
The component fire events to tell its user that there is something happened inside me.
Example of the three cases:
Your component my-form template:
<form>
<div class="row">
<slot></slot>
</div>
<div class="row">
<div class="col-12">
<button type="button" class="btn btn-default" #click="onSubmit"></button>
<button v-if="hasReset" class="btn btn-danger" #click="onReset"></button>
</div>
</div>
</form>
Your component js file:
export default {
name: 'my-form',
data() {
return {
}
},
props: {
reset: boolean
},
computed: {
hasReset: function(){
return this.reset;
}
}
methods: {
onSubmit: function(){
let data = { "name": "dummy data" };
this.$emit("submit", data);
},
onReset: function(){
let data = { "name": "" };
this.$emit("reset", data);
}
}
}
After that, you can use my-form component as below:
<my-form :reset="formHasReset" #submit="onFormSubmit" #reset="onFormReset">
<input class="col-12" type="text" name="name">
<input class="col-12" type="text" name="username">
<input class="col-12" type="password" name="password">
<input class="col-12" type="email" name="email">
</my-form>
And the javascript is:
data(){
formHasReset: true
},
methods: {
onFormSubmit: function(data){
console.log(data.name); //Should give you 'dummy data'
},
onFormReset: function(data){
console.log(data.name); //Should give you ''
}
}
I hope it is clear now for you :).

Use Modal as a template view and reference to it

I have modal code (below) wrapped in nav.html and it works as expected (login, logout...works).
<div class="modal fade" id="authModal" role="dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-body">
<form class="form-signin" role="form">
<input ng-model="user.email" type="email" class="form-control" placeholder="Email address" required="" autofocus="">
<input ng-model="user.password" type="password" class="form-control" placeholder="Password" required="">
<div class="checkbox checkbox-success">
<input ng-model="checkbox.signup" ng-init="checkbox.signup=false" type="checkbox">
<label> Sign Up for first-timer </label>
</div>
<div class="text-center">
<button ng-click="login($event)" class="btn btn-lg btn-primary" type="button">Sign In</button>
</div>
</form>
</div>
</div>
But when I move all modal content to a file named md.html and include it to nav.html via
<div class="navbar-header" ng-controller="MainCtrl">
<div ng-include="'views/modals/md.html'"></div>
</div>
It is absolute that I have it included in the ng-controller div.
On testing, I got error of unable to reference to user.password for the Controller. The controller works fine previously and I didn't change anything on it. For this question, I m posting a simplified version of modal and controller code.
$scope.login = function($event){ $event.preventDefault();
// console.log("cond ", cond, ".checkbox.signup ", $scope.checkbox.signup);
if (!$scope.logged)
fn.login($scope.user, function(){
if ($scope.checkbox.signup) fn.signup($scope.user);
});
};
var fn = {
login: function(user, cb){
if (Auth.authData) return;
if (!user.password) {
fn.alert("please type password");
return;
}
if (fn.valid_email(user.email))
Auth.ref_ds1.authWithPassword(user, function(error, authData) {
if (error) {
fn.alert(error);
cb();
} else {
authData.email = $scope.user.email;
console.log("Authenticated successfully on:", authData.email);
fn.greet("Hello " + authData.email.split("#")[0]);
$scope.logged = true;
window.location.href = "/";
}
});
}
}
How to reference them correctly?
It looks like you could be seeing issues with your ng-include creating another scope and you're not able to reference the previously defined user object.
One way I avoid confusion with scopes is using "Controller as" syntax to reference a scope specifically (see http://www.johnpapa.net/angularjss-controller-as-and-the-vm-variable/). Here's a tiny example:
// in the controller
app.controller('MainController', function() {
var vm = this;
this.somevalue = 'something';
})
// markup
<div ng-controller="MainCtrl as ctrl">
{{ ctrl.somevalue }}
<div ng-controller="SecondCtrl as secondCtrl">
{{ ctrl.somevalue }}
{{ secondCtrl.anothervalue }}
</div>
</div>
Using "Controller as" will really help unwind scope problems you're having, but it would take some re-tooling of your original controller.

How to update Parent form from a Modal

I have a modal form that updates a client's address once the "save" button is clicked. I want to use a AJAX call to update the Model's data once the modal form is closed. It would then redirect back to the parent form from which the modal form was called (Index.cshtml). The AJAX call is successfully retrieving the updated modal form's data via the textboxes but it always throws an error.
TL;DR: Want to close a modal form, redirect to parent form and update the text displayed there.
Please see below for my code snippets:
Controller
[ValidateInput(false), HttpPost]
public JsonResult UpdateClientDetails(Client newClientDetails)
{
_clientService.UpdateClient(newClientDetails);
return Json(newClientDetails);
}
$('.btn-update-client').click(function (e) {
var id = $(this).val();
$('#updateClientModal .modal-content').load('/client/UpdateClientDetails/' + id);
$('#updateClientModal').modal('show');
});
View (Index.cshtml)
<div class="panel-body">
<label>Client Id: <span id="ClientId">#id</span></label>
<address>
<span id="Address1">#client.Address1</span>, <span id="Address2">#client.Address2</span><br>
<span id="City">#client.City</span>, <span id="Province">#client.Province</span><br>
<span id="PostalCode">#client.PostalCode</span><br>
<abbr title="Phone">P:</abbr> <span id="PhoneNumber">#client.PhoneNumber</span>
</address>
<div><button value="#id" type="button" class="btn btn-primary btn-update-client">Change</button></div>
</div>
__
Controller Method
public ActionResult Index()
{
return View(_clientService.GetClientList());
}
Modal Form
#model Client
#using ProductManager.Models
<div class="modal-header">
<h4 class="modal-title" id="exampleModalLabel">#Model.Name - ID: #Model.Id</h4>
</div>
#{
var attributes = new Dictionary<string, object>();
attributes.Add("class", "form-horizontal");
}
#using (Html.BeginForm("UpdateClientDetails", "Client", FormMethod.Post, attributes))
{
<div class="modal-body">
<div class="form-group">
<label for="clientAddress1" class="col-xs-3 control-label">Address 1</label>
<div class="col-xs-9">
<input type="text" class="form-control" id="clientAddress1" name="Address1" value="#Model.Address1">
</div>
</div>
<div class="form-group">
<label for="clientAddress2" class="col-xs-3 control-label">Address 2</label>
<div class="col-xs-9">
<input type="text" class="form-control" id="clientAddress2" name="Address2" value="#Model.Address2">
</div>
</div>
<div class="form-group">
<label for="clientCity" class="col-xs-3 control-label">City</label>
<div class="col-xs-9">
<input type="text" class="form-control" id="clientCity" name="City" value="#Model.City">
</div>
</div>
<div class="form-group">
<label for="clientProvince" class="col-xs-3 control-label">Province</label>
<div class="col-xs-9">
#Html.DropDownListFor(model => model.Province, (IEnumerable<SelectListItem>)ViewBag.ProvinceList, new { #class = "form-control", #id = "clientProvince" })
</div>
</div>
<div class="form-group">
<label for="clientPostalCode" class="col-xs-3 control-label">Postal Code</label>
<div class="col-xs-9">
<input type="text" class="form-control" id="clientPostalCode" name="PostalCode" value="#Model.PostalCode">
</div>
</div>
<div class="form-group">
<label for="clientPhoneNumber" class="col-xs-3 control-label">Phone #</label>
<div class="col-xs-9">
<input type="text" class="form-control" id="clientPhoneNumber" name="PhoneNumber" value="#Model.PhoneNumber">
</div>
</div>
<div>
<input type="hidden" id="clientName" name="Name" value="#Model.Name">
</div>
<div>
<input type="hidden" id="clientID" name="Id" value="#Model.Id">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
}
<script type="text/javascript">
$('.btn-primary').click(function () {
$.ajax({
type: 'POST',
data: getModelData(),
dataType: 'json',
success: function (data) {
$("#Address1").text(data.Address1);
$("#Address2").text(data.Address2);
$("#City").text(data.City);
$("#Province").text(data.Province);
$("#PostalCode").text(data.PostalCode);
$("#PhoneNumber").text(data.PhoneNumber);
},
error: function () {
alert("Error occured!");
}
});
function getModelData() {
var dataToSubmit = {
Address1: $("#clientAddress1").val(),
Address2: $("#clientAddress2").val(),
City: $("#clientCity").val(),
Province: $("#clientProvince").val(),
PostalCode: $("#clientPostalCode").val(),
PhoneNumber: $("#clientPhoneNumber").val()
};
return dataToSubmit;
}
});
</script>
After clicking the "Save" button on my modal form, it redirects to http://localhost:6969/Client/UpdateClientDetails/1234 with the following string:
{"Address1":"38 Lesmill Rd","Address2":"Suite 1",
"City":"Toronto","Province":"ON","PostalCode":"M3B 2T5",
"PhoneNumber":"(416) 445-4504","Id":2827,"Name":"Advisor Centric"}
If you are being redirected when you click the save function, it could be due to a few reasons. The below snippet should solve your problems.
$(document).on('click', '.btn-primary', function (event) {
event.preventDefault();
$.ajax({
type: 'POST',
data: getModelData(),
dataType: 'json',
success: function (data) {
$("#Address1").text(data.Address1);
$("#Address2").text(data.Address2);
$("#City").text(data.City);
$("#Province").text(data.Province);
$("#PostalCode").text(data.PostalCode);
$("#PhoneNumber").text(data.PhoneNumber);
},
error: function () {
alert("Error occurred!");
}
});
function getModelData() {
var dataToSubmit = {
Address1: $("#clientAddress1").val(),
Address2: $("#clientAddress2").val(),
City: $("#clientCity").val(),
Province: $("#clientProvince").val(),
PostalCode: $("#clientPostalCode").val(),
PhoneNumber: $("#clientPhoneNumber").val()
};
return dataToSubmit;
}
});
Changes to snippet explained:
Instead of using the jQuery click method, I have updated this to use the on method. This will allow us to attach an event to the btn-primary class even if it is loaded after the dom has been rendered.
We are now passing in the event object into the method. This allows us to prevent any default behavior that is expected, for example submitting the form traditionally. This is accomplished with the event.preventDefault() method.

Categories

Resources