2

I have a code (not written by me) of a button that bookmarks a person and add it to a shortlist. It looks like this:

JS & Ajax part:

self.isShortlisted = ko.observable(@(Model.Application.IsShortlisted ? "true" : "false" ));

self.isHidden = ko.observable(@(Model.Application.IsHidden ? "true" : "false" ));

$('form#shortlistForm').ajaxForm(function () {
    viewModel.applicationViewModel.isShortlisted(true);
});

$('form#unshortlistForm').ajaxForm(function () {
    viewModel.applicationViewModel.isShortlisted(false);
});
Dukakus17
  • 1,221
  • 4
  • 15
  • 32
  • 1
    Please, don't ask as many questions about the same problem. Ask only one question and edit it to change its content. :-) – Jose Luis Jun 18 '17 at 10:22
  • Could you post the viewmodels `viewModel` and `applicationViewModel`? – Jose Luis Jun 18 '17 at 10:23
  • If `applicationViewModel` is an observable in your ViewModel, then you should write `viewModel.applicationViewModel().isShortlisted(true);` in your Ajax function. That is, add `()` to `applicationViewModel`. – Jose Luis Jun 18 '17 at 11:05
  • sorry about the duplicated question. I added the script section of the page that "requires" reloading to see the changes. Plz help – Dukakus17 Jun 18 '17 at 18:34
  • This sentence `self.applications = ko.observableArray(@Html.Json(Model.ApplicationCompatibilities.Select(o => o.JsonForm)) || []);` defines an observable array, but its content is not observable. When you change the property `isShortListed`, nothing happens, because is not an observable. You could force its content to be observable using the mapping plugin (http://knockoutjs.com/documentation/plugins-mapping.html), but then you have to change all your view model. – Jose Luis Jun 18 '17 at 20:01
  • When you change `isShortlisted` you can add this solution: https://stackoverflow.com/a/13231783/4065876. Here is a fiddle (https://jsfiddle.net/L39h30je/). The first time it shows `true, false, true`. If you click the button, the second value is changed to true, then it shows `true, true, true`. – Jose Luis Jun 18 '17 at 20:22
  • thank you so much. so how can i apply this to my code though? the one that you showed me is a hard-coded viewModel but mines retrieved from the server. Based on the viewModel that I wrote in my question, how can i apply that? – Dukakus17 Jun 18 '17 at 21:46
  • I edited and added the changed code. When I did that, it gave me an error that says : self.applications is not a function. Any idea? Also the thing with my code is that it "posts" it to a specific link which is /ajax-shortlist. Does your solution can be applied in this case too? – Dukakus17 Jun 18 '17 at 22:05

3 Answers3

1

AJAX stands for 'Asynchronous JavaScript and XML' and as you pointed out, it is used to perform tasks without having to reload the page.

What makes ajax work without reloading the page?

In answer to your question, tasks which are 'Asynchronous' can be carried out along side other tasks and do not need to wait for something else to finish (Synchronous). Because of this you do not need to reload / refresh a page to display new information as it's performed concurrently.

AJAX uses xhttp requests to usually return JSON objects from a web server. You can manipulate the DOM, JavaScript or HTML to display the object to the user.

You can read more about AJAX here

Hope this helped somewhat

Community
  • 1
  • 1
Coopza
  • 43
  • 4
0

Ajax is a client-side script that communicates to and from a server/database without the need for a postback or a complete page refresh.
The best definition for Ajax is this Ajax method use for exchanging data with server and it only updates parts of webpage

0

You are mixing jQuery with Knockout. The submit is handled by jQuery. If you use Knockout, let it to handle the submit event adding to the <form> this submit: submitShortlistForm,:

<form id="shortlistForm" data-bind="submit: submitShortlistForm, style: { display: application.isShortlisted === false ? 'inline-block' : 'none'}, attr: {action: '@(MVC.GetLocalUrl(MVC.HireOrgJobApplication.ViewApplication(Model.CurrentOrganization.CustomUrl, Model.Job.JobKey, "xxx/ajax-shortlist")))'.replace('xxx', application.applicationKey)}" method="post" style="display:inline;">
    @Html.AntiForgeryToken()
    <input type="hidden" name="ApplicationKey" data-bind="attr:{ value : application.applicationKey }" />
    <button type="submit" class="btn-act jui-tooltip" title="Shortlist">
        <i class="fa fa-2x fa-star"></i>
    </button>
</form>                 

Then, in your view model add this:

self.submitShortlistForm = function(){
    // I think is better to use $.post() or $.ajax().
    // I use the pluging because is in your question.
    $('form#shortlistForm').ajaxForm(function () {
        // Allways change position [0] of the observable array
        self.applications()[0].isShortlisted = true;

        var data = self.applications().slice(0);
        self.applications([]);
        self.applications(data);
    });
    $(this).ajaxSubmit();
}

In the Knockout submit event I bind the form with the ajaxForm plugin, and then I submit it. I'm not sure about jQuery Plugin, I would use $.post() or $.ajax().

You could find more information about Knockout submit in this link The "submit" binding.

I don't like this solution because you are removing all the content of the self.applications observable array. Is better to use the mapping plugin and convert all application objects (and its content) in observables. But with this approach, you should modify your ViewModel and the view.

Update 1 (19/06/2017)

If this <form> is inside a foreach loop, then the self.submitShortlistForm could be this:

self.submitShortlistForm = function(application){
    $('form#shortlistForm').ajaxForm(function () {
        // Updates the current row element.
        application.isShortlisted = true;

        var data = self.applications().slice(0);
        self.applications([]);
        self.applications(data);
    });
    $(this).ajaxSubmit();
}

And the html:

<form id="shortlistForm" data-bind="submit: $root.submitShortlistForm, ...">

Hope this helps.

Jose Luis
  • 994
  • 1
  • 8
  • 22
  • Thank you very much sir. But when I add this to my viewModel, it gives me a message saying "Uncaught ReferenceError: Unable to process binding "foreach: function (){return filteredApplications }" Message: Unable to process binding "submit: function (){return submitShortlistForm }" Message: submitShortlistForm is not defined" // I am assuming this happens because this form is inside a knockout foreach loop. Is there a solution to this error? – Dukakus17 Jun 19 '17 at 18:13
  • @user7677413 I updated my answer, hope this helps. If you keep getting this error, try to leave the body of `self.submitShortlistForm` empty, to discard any syntax error. In this fiddle (https://jsfiddle.net/L39h30je/2/) you have a running example; it shows three items; if you click in each one, it changes. – Jose Luis Jun 19 '17 at 19:31
  • Thanks. I am not getting an error anymore. But based on the condition of my HTML form, { display: application.isShortlisted === false }, shouldn't it disappear when I click the form since it will change "isShorlisted" to true? I also tried to use the console to change isShortlisted to true but it did not make any change to the button. – Dukakus17 Jun 19 '17 at 19:39
  • you can put a breakpoint in the `self.submitShortlistForm` function to see what happens with `self.applications()`. If this don't work your only solution is to make `isShortlisted` an observable using the mapping plugin (http://knockoutjs.com/documentation/plugins-mapping.html), and change all your model and view. – Jose Luis Jun 19 '17 at 20:53