ajax call does not work in angular js - ajax

I have the scenario as follow:
I have a text box and button and whenever I add sth in textbox I want to add the text in the table my code is as follow:
var app = angular.module('app', []);
app.factory('Service', function() {
var typesHash = [ {
id :1,
name : 'lemon',
price : 100,
unit : 2.5
}, {
id : 2,
name : 'meat',
price : 200,
unit : 3.3
} ];
var localId = 3;
var service = {
addTable : addTable,
getData : getData,
};
return service;
function addTable(name) {
typesHash.push({id:localId++, name:name, price:100,unit:1});
}
function getData() {
return typesHash;
}
});
app.controller('table', function(Service) {
//get the return data from getData funtion in factory
this.typesHash = Service.getData();
//get the addtable function from factory
this.addTable = Service.addTable;
});
and the plnkr is as follow:
plnkr
Now as you can see I add whatever inside the text in the table and everything works fine but now I want to add whatever inside the textbox and also I want to get some information from the servlet and add those to the table as well. so for that I use ajax call as follow:
function addTable(name) {
typesHash.push({id:localId++, name:name, price:100,unit:1});
var responsePromise = $http.get("http://localhost:8080/purchase/AddInfo");
responsePromise.success(function(data, status, headers, config) {
typesHash.push( {id:data.id,name : data.name, price : data.price,unit:2.5 });
});
}
but when I use that I get he following error:
ReferenceError: $http is not defined
can anyone help? (just a quick note: this code is smaller version of my real code and I purposely used factory since I need it)

inside of your controller attr your should insert an $http argument:
app.controller('CTRL1', function($scope, $http){
//Now your can use $http methods
})
or insert $http argument in your service decleration if you are using $http request methods from inside of your service

Related

Pass DataTable reference to the callback function on load

My current code is:
var CommissionLogs = $("#CommissionLogs").DataTable({
ajax: {
url: ajaxurl + '?action=pos&post_action=get_commissions'
},
'initComplete': function (settings, json){
//possible to access 'this'
this.api().columns(1);
}
});
I improved the code above as below with help :
var CommissionLogs = $("#CommissionLogs").DataTable({
ajax: {
url: ajaxurl + '?action=pos&post_action=get_commissions'
},
'initComplete': function(settings, json){
callbackFunction(settings);
}
});
function callbackFunction(settings){
var api = new $.fn.dataTable.Api( settings );
// api is accessible here.
}
Update :
Now I can access api from callback function. But I want use same callback with load() as below code.
CommissionLogs.ajax.url( newAjaxURL ).load( callbackFunction(), true);
But settings param is not accessible in load function.
I can clear and destroy datatable and re initialize always. But what will be the right way.
I think you need settings:
https://datatables.net/reference/type/DataTables.Settings
$('#example').dataTable( {
"initComplete": function(settings, json) {
myFunction(settings);
}
});
function myFunction(settings){
var api = new $.fn.dataTable.Api( settings );
// Output the data for the visible rows to the browser's console
// You might do something more useful with it!
console.log( api.rows( {page:'current'} ).data() );
}
Other option is re-use your var CommissionLogs variable throughout the code without using this, I recommend strongly this last option.
The dataTable.ajax.url().load() has not access to settings.
So can not call a callback function with settings.
But possible to use callback function without settings.
So here is an alternative way to use settings.
CommissionLogs.clear();// clear the table
CommissionLogs.destroy();// destroy the table
CommissionLogs = $("#CommissionLogs").DataTable({
ajax: {
url: newAjaxUrl
},
'initComplete': function (settings, json){
callbackDatatableFunciton(settings);
}
});

Navigate to another Page after appointment has been saved in kendo scheduler

I have got this scheduler displayed but not binding to tasks. The scheduler in the view. I am using java script method to read/create call to web api
#(Html.Kendo().Scheduler<TaskViewModel> ()
.Name("AppointmentSearchScheduler")
.DataSource(dataSource => dataSource
.Custom()
.Schema(schema => schema
.Model(m => {
m.Id(f => f.TaskID);
m.Field(f => f.OwnerID).DefaultValue(1);
}))
.Transport(new {
read = new Kendo.Mvc.ClientHandlerDescriptor() {
HandlerName = "customRead"
},
create = new Kendo.Mvc.ClientHandlerDescriptor() {
HandlerName = "customCreate"
}
})))
Below is javascript handler method I am not including create handler for brevity.
function customRead(options){
//get the selected Row of the kendo grid
var selectedRow = $("#locationgridKendo").find("tbody tr.k-state-selected");
var scheduler = $("#AppointmentSearchScheduler").data("kendoScheduler")
//get SelectedRow data
var rowData = $('#locationgridKendo').data("kendoGrid").dataItem(selectedRow);
if (rowData !== null) {
//Convert data to JSON
var rowDataJson = rowData.toJSON();
//extract the location ID
var locationId = rowDataJson.LocationID;
var CalenderweekStartDate = new Date().toISOString();
baseUrl = $('base').attr('href');
$.ajax({
url: baseUrl + 'Schedular/api/GetAppPerLocation?locationId=' + locationId + '&date=' + CalenderweekStartDate,
type: 'GET',
cache: false,
contentType: 'application/json',
success: function (result) {
//This method is hitting and i can see the data being returned
console.log('data is received : ' + result.Data);
options.success(result.Data);
},
error: function (xhr, status, error) {
//alert("Error: Search - Index.js - submitAppointment()");
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
}
});
}
}
Here is the web API controller called by making ajax call . The controller works perfectly when i used the basic read/create syntax . The ajax call complete and it does hit back the success method and returns the data but scheduler for some reason is not binded to incoming data. Here is my controller code
[HttpGet]
[Route("api/GetAppPerLocation")]
public DataSourceResult GetAppointmentPerLocation([ModelBinder(typeof(Usps.Scheduling.Web.ModelBinders.DataSourceRequestModelBinder))] DataSourceRequest request, int locationId, DateTime date) {
List < TaskViewModel > locationAvailableAppointmentList = new List < TaskViewModel > ();
locationAvailableAppointmentList = data.Select(appt => new TaskViewModel() {
TaskID = appt.ServiceAppointmentId,
Title = "Appointment Available",
Start = DateTime.SpecifyKind(appt.AppointmentBegin, DateTimeKind.Local),
End = DateTime.SpecifyKind(appt.AppointmentEnd, DateTimeKind.Local),
Description = "",
IsAllDay = false
}).ToList();
return locationAvailableAppointmentList.ToDataSourceResult(request);
}
For some reason the scheduler is not binding to incoming data . the incoming data works perfectly when i use a basic binding approach but not using transport . My goal for using this approach is once i am done with read(scheduler is not binding now) , on create I need to grab the ID of the newly created task returned by my controller and then pass that id to another mvc controller to render a confirmation page. Any other approach to accomplish this goal will be highly recommended.
Please excuse me for any mistake since this is my first question on stackoverflow.
My goal for using this approach is once i am done with read(scheduler is not binding now) , on create I need to grab the ID of the newly created task returned by my controller and then pass that id to another mvc controller to navigate render a confirmation page.
I speculated that read was not returning correct result so i had to fix that .Also my basic goal was redirection to another page after with appointment id and displaying a confirmation screen. This is how accomplished it . I understand this is not the best approach but it has been more than a year no body answered by question. Here is the approach i took .
I added a error to the model state like this in my controller
if (!String.IsNullOrEmpty(task.TaskID.ToString()))//redirect to confirmation page if the appointment was added to the queue
ModelState.AddModelError("AppointmentID", confirmationNumber);
then on client side i configure the error event on grid like this
.Events(
events => events.Error("RedirectToConfirmationPage"))
Here is the Javascript method details
function RedirectToConfirmationPage(e) {
console.log('RedirecToConfirmationPage method......');
console.log(e);
if (e.errors) {
var appointmentID = "";
// Create a message containing all errors.
$.each(e.errors, function (key, value) {
console.log(key);
if ('errors' in value) {
$.each(value.errors, function () {
appointmentID += this + "\n";
});
}
});
console.log('Newly Generated AppointmentID = ' + appointmentID);
// Redirect URL needs to change if we're running on AWS instead of on local developer machines
if (window.location.href.indexOf('/TestProject.Scheduling') > 1) {
window.location.href = '/Scheduler/AppointmentConfirmation?confirmationNumber=' + appointmentID
}
else {
window.location.href = '/Scheduler/AppointmentConfirmation?confirmationNumber=' + appointmentID
}
}
}
Hope it is helpfull to someone down the road.

AngularJS - testing factories which store state/data

I am working on new version of an app using legacy API (I have no controll of what the API returns etc.. ).
On the app init I request & store some site-wide info the factory which I have called stateFactory. Inside the stateFactory there is categories property (array of objects) which is storing the id -> category name relation.
Inside my app template I am using a filter to extract the name of the category by id {{ cat_id | categoryNameByIdFilter }} which is doing a lookup in the stateFactory.categories and returns the category name.
How do I write a unit test for such functionality (jasmine, mocha, chai, anything)?
// represantion of what the stateFactory looks like with some data in it
app.factory('stateFactory', ['', function(){
return {
categories = [
{ cat_id: 1, cat_name: "some category name" },
{ cat_id: 2, cat_name: "another category name" }
];
};
}])
// categoryNameByIdFilter
app.factory('categoryNameByIdFilter', ['stateFactory', function(stateFactiry){
return function(cat_id){
if ( !cat_id ) return null;
var cat_obj = _.findWhere(stateFactiry.categories, {
id: cat_id
});
if ( !cat_obj ) return null;
return cat_obj.cat_name;
};
}]);
I suggest using Jasmine and angular's mock module. You can create a mock of the stateFactory so that it does not hit a web service while unit testing. I have used Sinon to create my mocks and spies. You can, then, have angular inject your mock instead of the real service. This way, the only system under test is the categoryNameByIdFilter and not your web service.
// representation of what the stateFactory looks like with some data in it
app.factory('stateFactory', ['', function ()
{
return function ()
{
//This is the real stateFactory, which we are going to mock out.
};
}]);
// categoryNameByIdFilter - The system under test in this example
app.factory('categoryNameByIdFilter', ['stateFactory', '_', function (stateFactiry, _)
{
return function (cat_id)
{
if (!cat_id) return null;
var cat_obj = _.findWhere(stateFactiry.categories, {
id: cat_id
});
if (!cat_obj) return null;
return cat_obj.cat_name;
};
}]);
Given the code above, we can test categoryNameByIdFilter by doing this...
describe("categoryNameByIdFilter", function ()
{
beforeEach(module('YOUR_APP_MODULE'));
beforeEach(function ()
{
//The following line creates a mock of what we expect the state factory to return.
//We're mocking this because it is no the system under test, the filter is.
//A sinon 'stub' is a spy
mockStateFactory = sinon.stub({
categories: [
{ id: 1, cat_name: "some category name" },
{ id: 2, cat_name: "another category name" }
]
});
module(function ($provide)
{
//When Angular asks for a stateFactory, give them this mock instead
$provide.value('stateFactory', mockStateFactory);
});
});
//You can inject a filter using the "inject" method below
it("should filter by id", inject(function (categoryNameByIdFilter)
{
//Wrap categoryNameByIdFilter in a spy so that we can make assertions off of it.
var spy = sinon.spy(categoryNameByIdFilter);
var result = spy(1);
expect(result).toEqual("some category name");
expect(spy.calledBefore(mockStateFactory)).toBeTruthy();
expect(spy.returned("some category name")).toBeTruthy();
sinon.assert.calledOnce(spy);
spy(2);//Returns something besides "some category name"
expect(spy.alwaysReturned("some category name")).not.toBeTruthy();
sinon.assert.calledTwice(spy);
}));
});

Codeigniter rest issue with backbone

I just started using rest library wrote by Phil Sturgeon. I started using it by writing some simple examples. I short of get 'post' and 'get' work, but not for put and delete. I have some questions based on the code below.
// a simple backbone model
var User = Backbone.Model.extend({
urlRoot: '/user',
defaults:{
'name':'John',
'age': 17
}
});
var user1 = new User();
//user1.save(); // request method will be post unless the id attr is specified(put)
//user1.fetch(); // request method will be get unless the id attr is specified
//user1.destroy(); // request method will be Delete with id attr specified
In my CI REST controller
class User extends REST_Controller
{
public function index_get()
{
echo $this->get(null); //I can see the response data
}
public function index_post()
{
echo $this->post(null); //I can see the response data
}
public function index_put()
{
}
public function index_delete()
{
}
}
Basically, the get and post in the controller will be called when I save a model or fetch a model. With a id specified in the model, I can make a put or delete request to the server using model.save() and model.destroy(). however, I got a server error. it looks like index_put or index_delete can not be called. does anyone know How I can handle:
put request in the controller
delete request in the controller
get a single record with id specified
From the git, I only saw him to list index_post and index_put. there is no index_put and index_delete demo. should anyone can help me out? thanks
I faced the same exact problem, it looks like that DELETE, PUT, PATCH methods are not fully supported by browsers/html/server yet. You may want to look at this stack overflow question: Are the PUT, DELETE, HEAD, etc methods available in most web browsers?
A simple solution would be to change the methodMap of backbone line 1191 to the following:
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var methodMap = {
'create': 'POST',
'update': 'POST', //'PUT',
'patch': 'POST', //'PATCH',
'delete': 'POST', //'DELETE',
'read': 'GET'
};
and then include the action type as an attribute of the model
var Person = Backbone.Model.extend({
defaults:{
action_type : null,
/*
* rest of the attributes goes here
*/
},
url : 'index.php/person'
});
now when you want to save a model, do the following
var person = new Person({ action_type: 'create' });
person.set( attribute , value ); // do this for all attributes
person.save();
in the application/controllers folder you should have a controller called person.php with class named Person extending REST_Controller, that has the following methods:
class Person extends REST_Controller {
function index_get() { /* this method will be invoked by read action */ }
/* the reason those methods are prefixed with underscore is to make them
* private, not invokable by code ignitor router. Also, because delete is
* might be a reserved word
*/
function _create() { /* insert new record */ }
function _update() { /* update existing record */ }
function _delete() { /* delete this record */ }
function _patch () { /* patch this record */ }
function index_post() {
$action_type = $this->post('action_type');
switch($action_type){
case 'create' : $this->_create(); break;
case 'update' : $this->_update(); break;
case 'delete' : $this->_delete(); break;
case 'patch' : $this->_patch(); break;
default:
$this->response( array( 'Action '. $action_type .' not Found' , 404) );
break;
}
}
}
Having said that, this solution is an ugly one. If you scroll up in the backbone implementation, you will find the following code at line 1160:
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
// And an `X-HTTP-Method-Override` header.
if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
params.type = 'POST';
which means you need to set the emulate options of backbone configurations. add the following lines to your main.js
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;
To test the effect of that, I created a simple model and here are the results
you need a controller called Api in applications/controllers folder, in a file named api.php
<?php defined('BASEPATH') OR exit('No direct script access allowed');
require_once APPPATH.'/libraries/REST_Controller.php';
class Api extends REST_Controller
{
function index_get()
{
$this->response(array("GET is invoked"));
}
function index_put()
{
$this->response(array("PUT is invoked"));
}
function index_post()
{
$this->response(array("POST is invoked"));
}
function index_patch()
{
$this->response(array("PATCH is invoked"));
}
function index_delete()
{
$this->response(array("DELETE is invoked"));
}
}
and in your js/models folder, create a model called api_model.js
var Api = Backbone.Model.extend({
defaults:{
id: null,
name: null
},
url: "index.php/api/"
});
var api = new Api();
api.fetch({ success: function(r,s) { console.log(s); } }); // GET is invoked
api.save({},{ success: function(r,s) { console.log(s); } }); // POST is invoked
//to make the record old ( api.isNew() = false now )
api.save({id:1},{ success: function(r,s) { console.log(s); } }); // PUT is invoked
api.destroy({ success: function(r,s) { console.log(s); } }); //DELETE is invoked
I don't know how to do patch, but hope this helps.
Edit
I found out how to do patch, which is not included in the REST implementation of code ignitor. In REST_Controller line 39, you will find the following,
protected $allowed_http_methods = array('get', 'delete', 'post', 'put');
you need to add 'patch' at the end, to accept this method, also, after doing that add this code
/**
* The arguments for the PATCH request method
*
* #var array
*/
protected $_patch_args = array();
also, you need to add the following code to parse patch arguments:
/**
* Parse PATCH
*/
protected function _parse_patch()
{
// It might be a HTTP body
if ($this->request->format)
{
$this->request->body = file_get_contents('php://input');
}
// If no file type is provided, this is probably just arguments
else
{
parse_str(file_get_contents('php://input'), $this->_patch_args);
}
}
Now, according to backbone docs, you need to pass {patch: true} to send a PATCH method, when you call the following line, you execute a patch:
api.save({age:20},{patch: true, success: function(r,s) { console.log(s); } });
// PATCH is invoked

how to pass a parameter to actionlink from a script

I have a script:
function FindSerial() {
var textBoxValue = $("#clientSerial1").val();
return textBoxValue;
};
My actionlink is :
#Html.ActionLink("talks", "ClientTalks", "Talk", new { id ="FindSerial()" }, null)
I want to use the function in order to get id ; how can it be done?
#Jalai Amini is right. You will need to handle it with jquery. Something like this:
#Html.ActionLink("talks", "ClientTalks", "Talk", new { id="talklink"})
<script>
$(function () {
$('#talklink').click(function () {
document.location.href = $(this).attr("href") + "?id=" + FindSerial();
}
});
</script>
Something to consider:
In this way you are creating the url in the client side, so it can't use the mvc routes. In my example, it will be putting the id as a querystring parameter, but it could be another thing.

Resources