Knockout.JS 'enable' binding on length condition not working - javascript

All the data displaying and adding / deleting buttons seem to work until I change the delete button to do a check to make sure that there is always at least one person on the screen:
<!-- Check number of items before enabling delete button !-->
<button type="button" data-bind='enable: people().length > 1, click: $root.removePerson'>Delete</button>
The error is as follows:
Uncaught ReferenceError: Unable to process binding "foreach: function (){return people }"
Message: Unable to process binding "enable: function (){return people().length > 1 }"
Message: people is not defined
HTML
<div data-bind='foreach: people'>
<div class="personWell">
<input type="text" data-bind="value: name"></input>
<input type="text" data-bind="value: company"></input>
<button type="button" class="btn btn-sm btn-warning" data-bind='click: $root.removePerson'>Delete</button>
</div>
</div>
<button type="button" class="btn btn-sm btn-primary" data-bind='click:addPerson'>Add Person</button>
JavaScript
var ObservedPersonModel = function(people) {
var self = this;
self.people = ko.observableArray(people);
self.addPerson = function() {
self.people.push({
person_id:"",
name: "",
company: "",
positive_observation_id:""
});
};
self.removePerson = function(person) {
self.people.remove(person);
};
};
//originalPeopleObserved is a JSON encoded list of objects
var peopleViewModel = new ObservedPersonModel(originalPeopleObserved);
ko.applyBindings(peopleViewModel);
Resources
Here are some of the links where I learned about this functionality:
http://jsfiddle.net/rniemeyer/7RDc3/
http://knockoutjs.com/examples/gridEditor.html

Try this:
<button type="button" data-bind='enable: $root.people().length > 1, click: $root.removePerson'>Delete</button>

Actually i got your code running in a fiddle. First thing i changed was two > you forgot in your html code:
<input type="text" data-bind="value: name"></input>
<input type="text" data-bind="value: company"></input>
Then i added an empty object for testing:
originalPeopleObserved = null;
var peopleViewModel = new ObservedPersonModel(originalPeopleObserved);
ko.applyBindings(peopleViewModel);
And on Safari i can use your sample as expected.
Try this fiddle here

Related

Redirect location after ajax call in a click event

The code below is supposed to
Process the delete request when the delete a tag is select
redirect to the /projects webpage.
it seems like the redirect to /projects is occurring before the delete function gets a chance to run.
Is there a best practice that I'm missing here? or is there a better way to do this?
$(document).ready(function() {
$('#delete').click(function() {
var settings = {
url: `http://localhost:3000/projects/<%= project.id %>`,
method: 'DELETE',
timeout: 0,
};
$.ajax(settings).done(function(response) {
console.log(response);
});
});
});
<form class="update-project" method="POST" action="/update-project">
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroup-sizing-default">ID</span>
<input type="text" class="form-control" name="id" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" value="<%= project.id %>" disabled />
</div>
<a type="cancel" class="btn btn-secondary" href="/projects">Cancel</a>
<button type="submit" class="btn btn-primary float-right">Submit</button>
<a id="delete" type="delete" class="btn btn-danger" href="/projects"> DELETE </a>
</form>
I will try to answer using all the information the colleagues left in the comments.
We need to:
1 - Get the click button.
2 - Call event.preventDefault() to avoid refresh due to the <form method="POST" action=...>.
3 - Do the ajax request on the "click" event.
4 - In the ajax callback do the redirection.
Step by step:
1 - I will remove the href="/projects" from <a id="delete" type="delete" class="btn btn-danger" href="/projects"> DELETE </a>
2 - Add event.preventDefault() in the first line of the "click" callback.
3 - Add window.location.replace('/projects') in the first line of the ajax callback.
After all this it would look like:
<form class="update-project" method="POST" action="/update-project">
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroup-sizing-default">ID</span>
<input type="text" class="form-control" name="id" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" value="<%= project.id %>" disabled />
</div>
<a type="cancel" class="btn btn-secondary" href="/projects">Cancel</a>
<button type="submit" class="btn btn-primary float-right">Submit</button>
<a id="delete" type="delete" class="btn btn-danger"> DELETE </a>
</form>
$(document).ready(function() {
$('#delete').click(function(event) {
event.preventDefault();
var settings = {
url: `http://localhost:3000/projects/${project.id}>`,
method: 'DELETE',
timeout: 0,
};
$.ajax(settings).done(function() {
window.location.replace('/projects');
});
});
})
Note: I also want to add that the HTML structure doesn't make sense with what you want to do. You are creating an HTML form, but at the same time, you want to handle the form calls via JS instead of using the native HTML form you already have there. It should be refactored to get cleaner and less buggy-prone.
Note 2: You should not use <a> tags as buttons, buttons should be used as buttons because this is what they are :)
Issue ended up being another part of my code on the server side. I needed to return the status code in the express js router.put via return response.redirect(303, '/projects');
const express = require('express');
const ProjectModel = require('../src/controller/projectController');
const router = express.Router();
const controller = new ProjectModel();
module.exports = (params) => {
router.delete('/:id', async (request, response) => {
await controller.deleteById(request.params);
return response.redirect(303, '/projects');
});
return router;
}

How do I get the value of a text field using AngularJS?

I want to get the value of a text field value using AngularJS when a form is submitted.
The code below always shows "undefined".
html:
<form ng-submit="AdvanceSearchSubmit($event)" name="AdvanceSearch" novalidate>
<p ng-show="!AdvanceSearch.SearchKeyWord.$pristine && AdvanceSearch.SearchKeyWord.$invalid" class="text-danger">Text Cannot Be Empty!</p>
<div ng-hide="AdvanceSearchModel" class="input-group">
<input name="SearchKeyWord" ng-model="SearchKeyWord" id="SearchKeyWord" class="form-control" placeholder="Search in timeline...." type="text" required>
<span class="input-group-btn" ng-click="isAdvanceSearch='false'; SearchPost(0,'true')">
<button ng-disabled="AdvanceSearch.$invalid" type="submit" name="search" id="search-btn" class="btn btn-flat">
<i class="fa fa-search"></i>
</button>
</span>
</div>
</form>
one attempt:
$scope.AdvanceSearchSubmit = function(event)
{
alert(event.target.value);
};
another attempt:
$scope.AdvanceSearchSubmit = function(event)
{
alert(event.SearchKeyWord.value);
};
instead of event pass the SearchKeyWord as a parameter
ng-submit="AdvanceSearchSubmit(SearchKeyWord)"
controller
$scope.AdvanceSearchSubmit = function(keyWord)
{
alert(keyWord);
};
You don't need to pass the event at all to your AdvanceSearchSubmit on submit. You already have your values available inside $scope like ng-model for input field like ng-model="SearchKeyWord"
alert($scope.SearchKeyWord); //access value from `$scope` directly

AngularJS: Setting value of form field to various object properties

I have a simple AngularJS dynamic form that is bound by ng-model to a property modelParams.value. Each form field displays the value of modelParams.value However, I would like to have a button called "Default" that sets the values of all of the form fields to some other property in this associative array such as modelParams.defaultValue, or modelParams.oldValue. I assume that once the "Default" button is pressed this would override the value of ng-model="modelParams.value".
Here is the form:
<form name="modelParamsForm">
<div class="form-group" ng-repeat="modelParam in modelParams">
<div class="row">
//INPUT FORM FIELDS
<input type="number" class="form-control input-sm" required ng-
model="modelParam.value" >
</div>
</div>
<button class="btn btn-primary btn-sm" ng-
click="updateModelParams(modelParams, modelParamsForm)">
</button>
//DEFAULT BUTTON
<button type="button" class="btn btn-default btn-sm" ng-
click="default()">Default</button>
</form>
My JSON looks like this:
[{"model":"MAF","paramname":"CascDefaultSpreadOverride","minvalue":"0","maxvalue":"100","description":"The defaault repo spread override to use for CASC positions.","defaultvalue":1.0,"value":1.0,"datatype":"FLOAT"},{"model":"MAF","paramname":"DefaultLotSize","minvalue":"1","maxvalue":"1000","description":"The minimum lot size that must be met for a collateral allocation.","defaultvalue":1.0,"value":1.0,"datatype":"INTEGER"},{"model":"MAF","paramname":"HtbColdHaircut","minvalue":"0","maxvalue":"100","description":"The haircut to apply to positions with a Cold HTB category.","defaultvalue":0.1,"value":0.1,"datatype":"FLOAT"},{"model":"MAF","paramname":"HtbExtraHotHaircut","minvalue":"0","maxvalue":"100","description":"The haircut to apply to positions with a Extra-Hot HTB category.","defaultvalue":0.9,"value":0.9,"datatype":"FLOAT"},]
$scope.field = 'value';
$scope.change = function() {
$scope.field = 'oldValue';
}
...ng repeat blabla
<input ng-model="modelParam[field]"/>
...
<button ng-click="change()">Change</button>
EDIT: Here is a working demo: http://jsfiddle.net/zy94an54/

Customized buttons

I am using xeditable for my project.
Fiddle
Above is the fiddle.
I want to have save and send invite button instead of save button only while click on add button.
When I click on edit it should be Save button.
I tried using another forom to display save and send invite button with no result.
<form editable-form name="rowform" id="hidebuttons12" ng-show="rowform.$visible" class="form-buttons form-inline" shown="">
<button type="button" ng-disabled="rowform.$waiting" ng-click="rowform.$cancel(); isCollapsed2 = !isCollapsed2" ng-hide="hideButton[$index]" class="btn btn-default">cancel</button>
<button type="submit" ng-click="saveUser(); isCollapsed2 = !isCollapsed2" ng-disabled="rowform.$waiting" ng-hide="hideButton[$index]" class="btn btn-primary">Save changes</button>
</form>
<form class="text-right" editable-form name="rowform1" ng-show="rowform1.$visible" class="form-buttons form-inline" shown="inserted == user">
<button type="button" ng-click="removeUser($index);" class="btn btn-default">cancel</button>
<button type="button" ng-click="saveUser(); sendInvite(); isCollapsed2 = !isCollapsed2" ng-disabled="rowform1.$waiting" class="btn btn-primary">{{buttonText}}</button>
</form>
Or can we have all three buttons in one form and hide and show it based on button click.
Can anyone help me with this issue.
Edit : Following your comment, new Fiddle : http://jsfiddle.net/NfPcH/11280/
The same way, you just need to add : ng-show="user.id < 0" to the save button
I updated your fiddle :
http://jsfiddle.net/NfPcH/11278/
I'm not an expert in xeditable so maybe there is a better solution.
The solution I used is setting user.id = -1 when you add new user.
And setting user.id = users.length+1 only during save.
Therefore you can use ng-show="user.id < 0" on the button you want to show only for new users.
Code:
$scope.saveUser = function (data, user) {
//$scope.user not updated yet
user.id = $scope.users.length + 1;
angular.extend(data, {
id: user.id
});
return $http.post('/saveUser', data);
};
// add user
$scope.addUser = function () {
$scope.inserted = {
id: -1,
name: '',
status: null,
group: null
};
$scope.users.push($scope.inserted);
};
View:
<button type="button" ng-show="user.id < 0" ng-click="saveUser(); sendInvite();" ng-disabled="rowform.$waiting" class="btn btn-primary">Send invite</button>

Why this submit function in Meteorjs doesn't work?

I have a form which consists of 7 questions. I ask them individually using display:none. But the problem is that submit function doesn't work. When I click it, it just redirects back to the first question and url turns to - http://localhost:3000/?problem=&why1=&why2=&why3=&why4=&why5=&solution=&submit-all=Answer . I really need help with this please. Below is code for HTML template and JavaScript submit function to submit in Problems collection.
<template name="submitProblem">
<div class="container">
<div class="main-page">
<form class="text-center">
<div id="submit-problem">
<input autofocus="autofocus" type="text" name="problem" id="problem" placeholder="What's the problem ?"/>
<input type="button" id="route" value="Find Its Route" class="route btn btn-sample">
</div>
...
submit-why1 - submit-why4
...
<div id="submit-why5" class="hidden">
<input autofocus="autofocus" type="text" id="why5" class="" name="why5" placeholder="This problem exists, because..."/>
<input type="button" value="Answer" class="btn-success btn answer5">
<button class="btn back5 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
<div id="submit-solution" class="hidden">
<input autofocus="autofocus" type="text" name="solution" id="solution" placeholder="What could be the best solution ?"/>
<input type="submit" id="submit-all" name="submit-all" value="Answer" class="btn btn-primary submit-all">
<button class="btn back6 back-btn"><i class="fa fa-arrow-left fa-3x"></i></button>
</div>
</form>
</div>
</div>
</template>
Template.submitProblem.events({
'submit .submit-all':function() {
event.preventDefault();
var problem = $(event.target).find('[name=problem]').val();
var why1 = $(event.target).find('[name=why1]').val();
var why2 = $(event.target).find('[name=why2]').val();
var why3 = $(event.target).find('[name=why3]').val();
var why4 = $(event.target).find('[name=why4]').val();
var why5 = $(event.target).find('[name=why5]').val();
var solution = $(event.target).find('[name=solution]').val();
Problems.insert({
problem: problem,
why1: why1,
why2: why2,
why3: why3,
why4: why4,
why5: why5,
solution: solution,
submitdate: new Date()
});
console.log(problem + why1 + why2 + why3 + why4 + why5 + solution);
Router.go('submitted');
}
});
You need to pass the event as the first parameter to your handler:
submit: function(event) {
event.preventDefault();
...
Otherwise it won't be defined, the default action (a POST) won't be prevented, and your page will reload.

Categories

Resources