Knockout JS calling functions on load - javascript

I am using Knockout.js to build a client-side view model. In my view model I would like to expose some functions that can be bound to elements in the page (typical MVVM model). I only want these functions to be called in response to a click event from a button, however they are been called when the view model is been constructed...
I have defined my model like this:
<script type="text/javascript">
var ViewModel = function(initialData) {
var self = this;
self.id = initialData;
self.isSubscribed = ko.observable(false);
self.name = ko.observable();
self.SubscribeToCategory = function () {
$.ajax({
url: '#Url.Action("Subscribe", "Category")',
type: 'POST',
data: {
categoryId: self.id
},
success: function () {
self.isSubscribed(true);
},
failure: function () {
self.isSubscribed(false);
}
});
alert('Subscribing...');
};
self.UnsubscribeFromCategory = function () {
$.ajax({
url: '#Url.Action("Unsubscribe", "Category")',
type: 'POST',
data: {
categoryId: self.id
},
success: function () {
self.isSubscribed(false);
},
failure: function () {
self.isSubscribed(true);
}
});
alert('Unsubscribing...');
};
self.LoadCategory = function () {
$.ajax({
url: '#Url.Action("GetCategory", "Category")',
type: 'POST',
async: true,
data: {
categoryId: self.id
},
dataType: 'json',
success: function (data) {
self.isSubscribed(data.IsSubscribed);
self.name(data.Name);
}
});
};
self.LoadCategory();
};
$(document).ready(function () {
var data = '#Model';
var viewModel = new ViewModel(data);
ko.applyBindings(viewModel);
});
When I execute the code however, the two alerts fire automatically, but I am not expecting them to. I am using ASP MVC4, and the HTML that is using the view model is below:
<p>
ID: <span data-bind="text: id"></span>
</p>
<div id="subscribe" data-bind="visible: isSubscribed == false">
<button data-bind="click: SubscribeToCategory()">Subscribe</button>
</div>
<div id="unsubscribe" data-bind="visible: isSubscribed == true">
<button data-bind="click: UnsubscribeFromCategory()">Unsubscribe</button>
</div>
<div>
Category Name: <span data-bind="text: name"></span>
Is Subscribed: <span data-bind="text: isSubscribed"></span>
</div>
I've looked through the tutorials online and some other knockout samples, as well as other places in my code where I have used knockout, but I cannot see why the two functions (SubscribeToCategory and UnsubscribeFromCategory) are firing on document load.

jsfiddle
It took me a second, but ended up being a simple fix. remove the () from your data-bind="click: SubscribeToCategory()" and make both you click handlers this data-bind="click: SubscribeToCategory" and data-bind="click: UnsubscribeFromCategory"

It appears that the brackets in the function name in the binding <button data-bind="click: SubscribeToCategory()">Subscribe</button> is the problem.
The ()'s shouldn't be there. So it should look like:
<button data-bind="click: SubscribeToCategory">Subscribe</button>

Related

How to pass the id in vue js for the post ajax request?

I need to pass an "id" obtained as data in vue js? I am getting id as "agnt.basic.actor". Since there are many id's present, how can i able to pass the same
<tr v-for="agnt in agentlist">
<td v-if="agnt.basic">{{agnt.basic.actor}}</td>
<td v-if="agnt.basic">{{agnt.basic.name}}</td>
<td v-if="agnt.basic">{{agnt.basic.email}}</td>
<td v-if="agnt.basic">{{agnt.basic.phone}}</td>
<td v-if="agnt.basic"><a v-bind:href="'/agentpendingdetails/'+agnt.basic.actor">Basic Details</a></td>
<td> <form method="POST" v-on:submit.prevent="handelSubmit();">
<div class="text-center">
<button type="submit" class="btn btn-info btn-fill btn-wd"><a v-bind:value="agnt.basic.actor"> Verify</a></button>
</div>
<div class="clearfix"></div>
</form></td>
</tr>
When I click on submit button i need to pass the id obtained from "agnt.basic.actor".
How can I able to implement the same? Please help me.
My vue js code is
<script>
dash = new Vue({
el: '#dash',
data: {
agentlist: {
basic: [],
},
authType: '{{ uid }}',
id: '',
},
mounted() {
var self = this;
data = {};
data['auth-token'] = this.authType;
$.ajax({
url: "http://alpha/admin/get/agents/pending/",
data: data,
type: "POST",
dataType: 'json',
success: function (e) {
if (e.status == 1) {
self.agentlist = e.data
}
},
});
},
methods: {
handelSubmit: function (e) {
var vm = this;
data = {};
data['auth-token'] = this.authType;
data['uid'] = this.uid;
$.ajax({
url: 'http://127.0.0.1:8000/alpha/admin/verify/user/',
data: data,
type: "POST",
dataType: 'json',
success: function (e) {
if (e.status) {
vm.pid = e.pid;
console.log(vm.pid);
}
else {
vm.response = e;
}
}
});
return false;
},
},
})
</script>
So, how can I able to pass the id? Please help me to obatain the result.
Instead of using form tag just use a normal button to submit the form and pass the current agnt data to submit function.
So your HTML Should be
<tr v-for="agnt in agentlist">
<td v-if="agnt.basic">{{agnt.basic.actor}}</td>
<td v-if="agnt.basic">{{agnt.basic.name}}</td>
<td v-if="agnt.basic">{{agnt.basic.email}}</td>
<td v-if="agnt.basic">{{agnt.basic.phone}}</td>
<td v-if="agnt.basic"><a :href="'/agentpendingdetails/'+agnt.basic.actor">Basic Details</a></td>
<td>
<button #click="handleSubmit(agnt)" class="btn btn-info btn-fill btn-wd">Verify</button>
</td>
</tr>
and method should be,
handleSubmit: function (agnt) {
var vm = this;
data = {};
data['auth-token'] = this.authType;
data['uid'] = this.uid;
data['agent-actor'] = agnt.basic.actor
$.ajax({
url: 'http://127.0.0.1:8000/alpha/admin/verify/user/',
data: data,
type: "POST",
dataType: 'json',
success: function (e) {
if (e.status) {
vm.pid = e.pid;
console.log(vm.pid);
} else {
vm.response = e;
}
}
});
return false;

How to set the id for the new created item with Knockout

The problem is that I cannot update a new created item, because on the server I receive no Id.
I am trying to learn Knockout, and I am not able to find a way to provide the Id to new created items.
I have an object with Id, and Name, using knockout I can make all Crud operations, but, after inserting a new item, if I try to change his name I am not able because that item has no Id value.
My question is: Every time when I add a new item I need to get a fresh collection of items back to the view, and rebind the view?
or, there is a way to another way to provide the Id to the new inserted items?
Here is my code:
function Person(id, name) {
var self = this;
self.Id = ko.observable(id);
self.nume = ko.observable(name);
}
function PersonVm() {
var self = this;
self.Persons = ko.observableArray([]);
self.newPerson = ko.observable(new Person())
self.isModificare = false;
self.addPerson = function () {
if (!self.isModificare) {
$.ajax("/Person/AddPerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) { alert(result.mesaj); }
});
} else {
$.ajax("/Person/UpdatePerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) { alert(result) }
});
}
self.isModificare = false;
if (!self.isModificare) self.Persons.unshift(self.newPerson());
self.newPerson(new Person());
}
self.removePerson = function () {
$.ajax("/Person/DeletePerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) { alert(result) }
});
self.Persons.remove(self.newPerson());
self.newPerson(new Person());
}
self.ModificaPerson = function (person) {
self.newPerson(person);
self.isModificare = true;
}
$.getJSON("/Person/GetPersons", function (allData) {
var mapPerson = $.map(allData, function (item) { return new Person(item.Id,item.Name) });
self.Persons(mapPerson);
});
}
ko.applyBindings(new PersonVm());
Edit:
This is the view:
<div class="input-group">
<input type="text" class="form-control" data-bind="value: newPerson().name">
<span class="input-group-btn">
<button class="btn btn-default" data-bind="click:addPerson">
<span class="glyphicon glyphicon-plus-sign" style="color:green"></span>
</button>
</span>
<span class="input-group-btn">
<button class="btn btn-default" data-bind="click:$root.removePerson">
<span class="glyphicon glyphicon-trash" style="color:red"></span>
</button>
</span>
</div>
<ul data-bind="foreach: Perons" class="list-group" id="content">
<li class="list-group-item" data-bind="text: name,click:$root.ModificaPerson"></li>
</ul>
Two steps to get what you want:
Ensure that your "Person/AddPerson" Web service return the ID of the created object.
Change your update method so that it sets an ID on the newPerson property:
$.ajax("/Person/AddPerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) {
self.newPerson().Id(result.Id);
}
});
Note that the above code supposes that your services returns a JSON object with an ID property named 'Id'.

how to bind selectlist to value using json in javascript

I'm new to web application development and i need to bind values which i retrieved from json object. i tried several ways but couldn't able to bind values to my combo box.
<script type="text/javascript">
var ViewModel = {
CheckIn : ko.observable(),
CheckOut: ko.observable(),
Lunch: ko.observable(),
Rest: ko.observable(),
WorkOnProject: ko.observable(),
Projects: ko.observableArray()
};
this.GetProjects = function () {
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (arg) {
for (var i = 0; i < arg.d.length ; i++) {
var value = arg.d[i].ProjectCode;
var option = new Option(arg.d[i].ProjectCode, arg.d[i].ProjectCode);
Select1.add(option, null);
}
},
error: function (arg) {
}
});
};
ko.applyBindings(ViewModel);
</script>
My HTML Code:
<tr>
<td class="auto-style1">Project Code </td>
<td ><select id="Select1" data-bind='options: Projects' style="width: 312px"></select>
<button data-bind='click: GetProjects'>Cancel</button>
</td>
</tr>
My Sever Side Coding :
[WebMethod]
public static object ReturnComplexType()
{
List<Project> projects = new List<Project>();
Project p = new Project();
p.ProjectID = 1;
p.ProjectCode = "ABC";
p.ProjectName = "Test";
projects.Add(p);
Project p2 = new Project();
p2.ProjectID = 2;
p2.ProjectCode = "DEF";
p2.ProjectName = "xsd";
projects.Add(p2);
return projects;
}
Your structure is way off, you're mixing object instances with function on the window object..
This is one way of solving it
ViewModel = function() {
this.CheckIn = ko.observable();
this.CheckOut = ko.observable();
this.Lunch = ko.observable();
this.Rest = ko.observable();
this.WorkOnProject = ko.observable();
this.Projects = ko.observableArray()
};
ViewModel.prototype = {
GetProjects: function () {
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
this.Projects(data);
}.bind(this),
error: function (arg) {
}
});
};
};
ko.applyBindings(new ViewModel());
What I did was to move the GetProjects function to the model object
Your select box is bound to the Projects observable but you don't set an explicit text/value
<select id="Select1" data-bind='options: Projects, optionsText: 'ProjectName', optionsValue:'ProjectID', value: SelectedProjectId"' style="width: 312px"></select>
The SelectedProjectId would be another observable in your model if you need to save the value somewhere.
The other thing you'll want to change is filling the actual observable array instead of select box directly.
<script type="text/javascript">
function ViewModel() {
var self = this;
self.CheckIn = ko.observable();
self.CheckOut = ko.observable();
self.Lunch = ko.observable();
self.Rest = ko.observable();
self.WorkOnProject = ko.observable();
self.Projects = ko.observableArray();
};
var VM = new ViewModel();
ko.applyBindings(ViewModel);
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (arg) {
for (var i = 0; i < arg.d.length ; i++) {
VM.Projects.push(d[i]);
}
},
error: function (arg) {
}
});
</script>
After you get things binding right you'll probably want to swap out the VM.Projects.push() for a speedier way.
Calling .push() when you're filling up arrays on initial load triggers a ton of notifications that can really make the page crawl.

How to remove data from view run-time?

I am developing MVC application and using razor syntax.
In this application I am giving comment facility.
I have added a partial view, which loads the comment/Records from DB.
In below image, we can see the comment box which is called run-time for employee index view.
problem is, when user delete comment, its get deleted from DB but how to remove it from the screen without redirect to any page ?
I wan to remove that deleted comment div tag smoothly...
Please see the image...
my code is...
#model IEnumerable<CRMEntities.Comment>
#{
<div class="ParentBlock">
#foreach (var item in Model)
{
<div class="OwnerClass" id="OwnerName" data-comment-id="#item.Id">
<span class="EmpName"> #Html.ActionLink(item.Owner.FullName, "Details", "EMployee", new { id = item.OwnerId }, new { #style = "color:#1A6690;" })</span>
#Html.DisplayFor(ModelItem => item.CommentDateTime)
<span class="EmpName"><button type="button" class="deleteComment">Delete</button></span>
<p class="CommentP">
#Html.DisplayFor(ModelItem => item.CommentText)
</p>
<br />
<a class="Delete222" style="cursor:move;display:none;">DeleteNew</a>
<br />
</div>
}
<p class="p12">
</p>
</div>
<p id="ClassPara" class="ShowComments" onclick="chkToggle()">Show All Comments</p>
}
#Html.TextArea("Comment", "", 5, 80, "asdsd")
<input type="button" value="Add Comment" id="AddCommentButton"/>
<input type="button" value="Clear" onclick="clearText()"/>
<br />
</body>
</html>
<script src="../../Scripts/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$(".deleteComment").click(function () {
alert("asd");
var commentBlock = $(this).parent('.OwnerClass');
commentBlock.hide('slow')
});
});
$(document).ready(function () {
$('.OwnerClass').hover(function () {
$('.Delete222', this).show();
}, function () {
$('.Delete222').hide();
});
});
</script>
Instead of generating action link, place there button or . Bind JavaScript function to click event on this button, in this function make ajax call to action that deletes comment from db and use Jquery to hide proper div.
<span class="EmpName"><button type="button" class="deleteComment">Delete</button></span>
JavaScript:
$('.deleteComment').click(function ()
{
var commentBlock = $(this).parent('.ParentBlock');
$.ajax({
type: 'post',
url: '/Comment/DeleteComment',
dataType: 'json',
data:
{
commentId: getCommentId(commentBlock )
},
success: function (data) {
commentBlock.hide('slow')
}
});
});
UPDATE:
Update due to question update and comments below this answer:
$(document).ready(function () {
$(".deleteComment").click(function () {
var commentBlock = $(this).parent('.OwnerClass');
$.ajax({
type: 'post',
url: '/Comment/DeleteComment',
dataType: 'json',
data:
{
commentId: commentBlock.attr('data-comment-id')
},
success: function (data) {
commentBlock.hide('slow')
}
});
});
});

KnockoutJS race condition during ajax call

Here is a weird race condition happening with knockoutjs. I'm setting two observables independantly using ajax calls. One is a list, the other is a single value. The weird thing is when I load the single value before the list, it won't bind correctly. Any suggestions?
JsFiddle: http://jsfiddle.net/JasonMore/bxfXd/110/
View
<form data-bind='submit:addItem'>
Add item: <input data-bind='value:itemToAdd, valueUpdate: "afterkeydown"' type='text' />
<button data-bind='enable: isAddButtonEnabled' type='submit'>Add</button>
</form>
<p>Your values:</p>
<select data-bind='options:allItems, value:selectedItems' height='5'> </select>
<div>
<button data-bind='click: removeSelected'>Remove</button>
<button data-bind='click: function() { allItems.sort() }, enable: allItems().length > 1'>Sort</button>
</div>
</div>
Code
var betterListModel = function() {
var self = this;
// properties
this.itemToAdd = new ko.observable("");
this.allItems = new ko.observableArray();
this.selectedItems = new ko.observable('');
// computed
this.isAddButtonEnabled = ko.computed(function() {
return self.itemToAdd().length > 0
});
//methods
this.addItem = function() {
if ((this.itemToAdd() != "") && (this.allItems.indexOf(this.itemToAdd()) < 0)) this.allItems.push(this.itemToAdd());
this.itemToAdd("");
}
this.removeSelected = function() {
this.allItems.removeAll(this.selectedItems());
this.selectedItems();
} };
var view = new betterListModel();
ko.applyBindings(view);
// load $.ajax({
url: '/echo/json/',
type: 'post',
data: {
json: $.toJSON("Ham"),
delay: 1
},
success: function(data) {
view.selectedItems(data);
} });
$.ajax({
url: '/echo/json/',
type: 'post',
data: {
json: $.toJSON(["Fries", "Eggs Benedict", "Ham", "Cheese"]),
delay: 2
},
success: function(data) {
$.each(data, function(index, value) {
view.allItems.push(value);
});
} });
Try this-->
// Whenever the states changes, reset the selectedState selection
this.allItems.subscribe(function () {
this.selectedItems(arrayOfMySelectedItems);
});

Categories