Angular Material Design - Creating a new Chip with Autocomplete - angularjs

I'm using Angular Material Design. I have a field that contains an autocomplete set of terms. This list is pulled in via a api call.
However, if the user decides to create a new title (chip), I'm using md-transform-chip="vm.transformChip($chip)".
Now, when a new chip is found, I want to create the Job Title via a api call, then return the response and have that be the new chip.
But, what I'm finding out, if I make the api call and in the success callback, return the chip, it's always a empty chip. If I don't make the api call and just return the new chip, it displays correctly.
Ex. of it not working:
function transformChip(chip) {
// If it is an object, it's already a known chip
if (angular.isObject(chip)) {
return chip;
}
api.jobTitles.create.save({'site_id': vm.site_id}, { name: chip },
// Success
function (response) {
vm.jobTitles.push(response);
return { name: response.name, _id: response._id}
},
// Error
function (response) {
}
);
}
Ex. pulled from Angular Material Design's site, where it does work.
function transformChip(chip) {
// If it is an object, it's already a known chip
if (angular.isObject(chip)) {
return chip;
}
return { name: chip, type: 'new' }
}
My goal, is to create the new chip before the submission of the form and add the new chip to the array of jobtitles, that way, any new submission, will have the chip for the typeahead.
Thanks for your help.

You just have to return null after you've pushed the new jobtitle.
You may would like to put some load element ou disable the input untill the request is over, because if the request takes time the user will see nothing until it's over. I would prefer to just disable the input untill the request is over and the element has been successfully pushed into the scope.
If you check the attributes table in the documentations you will se that
https://material.angularjs.org/latest/api/directive/mdChips

Related

Handling device data using ionic v2 and the BLE Central plugin

I've been having some issues with how to best handle the device data of discovered peripherals and wanted to see if anyone can shine some light on this.
I am able to scan for devices perfectly fine, and my "success" callback works as well. What I want to do is create a list that displays the found devices and connects to the one that is selected. I have no problem with creating the list with ng repeat, however I am unsure as to how to proceed with the data that is returned by the success function. How can I go about saving each peripheral into an array so that I can access each individual peripheral's name, id , rssi, etc? I have tried something along the lines of creating an array outside the function to store the peripherals in, and this works perfectly fine inside the starScanning function, however I can't push them into an array from inside the success callback function. If I just store the scan results into an array from inside the startScanning function, is that sufficient?
startScanning = function() {
this.ble.startScan([], this.success).subscribe(device => {
console.log(JSON.stringify(device.name));
});
this.isScanning = true;
this.presentLoading();
setTimeout(() => {
this.ble.stopScan().then(() => {
console.log("Scanning has stopped");
this.isScanning = false;
});
}, 3000);
}
success = function(peripheral) {
console.log("Success Callback called");
console.log(peripheral.rssi);
}
You can handle data returned from the scan in the subscribe callback (the startScan method is supposed to only take an array of services as the parameters according to the docs:
this.scanSubscription = this.ble.startScan([])
.subscribe( device => {
// device will have an id property that you can use to connect
this.devices.push(device); // devices is an array on your component
});
Now, you can use *ngFor to loop over the devices array and attach a click handler that passes the device's id:
<ion-list>
<ion-item *ngFor="let device of devices" (click)="connectToDevice(device.id)">{{device.id}}</ion-item>
</ion-list>
The connectToDevice() takes a device id and connects:
connectToDevice(id: string) {
this.connectSubscription = this.ble.connect(id)
.subscribe((data) => {
console.log('Successfully connected!');
});
}
A couple of notes:
It's considered good practice to store subscriptions as properties of your page/component so that you can call unsubscribe()on them when a page/component is destroyed to prevent memory leaks
I'd recommend checking out the startScanWithOptions function since you can pass the option reportDuplicates with a value of false to ignore duplicate devices
Check out my Github repo (especially the page file bluetooth.ts) for a working demo app (this uses the startScanWithOptions function I mentioned above, but the functionality is the same)

My flux store gets re-instantiated on reload

Okay. I'm kinda new to react and I'm having a #1 mayor issue. Can't really find any solution out there.
I've built an app that renders a list of objects. The list comes from my mock API for now. The list of objects is stored inside a store. The store action to fetch the objects is done by the components.
My issue is when showing these objects. When a user clicks show, it renders a page with details on the object. Store-wise this means firing a getSpecific function that retrieves the object, from the store, based on an ID.
This is all fine, the store still has the objects. Until I reload the page. That is when the store gets wiped, a new instance is created (this is my guess). The store is now empty, and getting that specific object is now impossible (in my current implementation).
So, I read somewhere that this is by design. Is the solutions to:
Save the store in local storage, to keep the data?
Make the API call again and get all the objects once again?
And in case 2, when/where is this supposed to happen?
How should a store make sure it always has the expected data?
Any hints?
Some if the implementation:
//List.js
componentDidMount() {
//The fetch offers function will trigger a change event
//which will trigger the listener in componentWillMount
OfferActions.fetchOffers();
}
componentWillMount() {
//Listen for changes in the store
offerStore.addChangeListener(this.retriveOffers);
}
retrieveOffers() {
this.setState({
offers: offerStore.getAll()
});
}
.
//OfferActions.js
fetchOffers(){
let url = 'http://localhost:3001/offers';
axios.get(url).then(function (data) {
dispatch({
actionType: OfferConstants.RECIVE_OFFERS,
payload: data.data
});
});
}
.
//OfferStore.js
var _offers = [];
receiveOffers(payload) {
_offers = payload || [];
this.emitChange();
}
handleActions(action) {
switch (action.actionType) {
case OfferConstants.RECIVE_OFFERS:
{
this.receiveOffers(action.payload);
}
}
}
getAll() {
return _offers;
}
getOffer(requested_id) {
var result = this.getAll().filter(function (offer) {
return offer.id == requested_id;
});
}
.
//Show.js
componentWillMount() {
this.state = {
offer: offerStore.getOffer(this.props.params.id)
};
}
That is correct, redux stores, like any other javascript objects, do not survive a refresh. During a refresh you are resetting the memory of the browser window.
Both of your approaches would work, however I would suggest the following:
Save to local storage only information that is semi persistent such as authentication token, user first name/last name, ui settings, etc.
During app start (or component load), load any auxiliary information such as sales figures, message feeds, and offers. This information generally changes quickly and it makes little sense to cache it in local storage.
For 1. you can utilize the redux-persist middleware. It let's you save to and retrieve from your browser's local storage during app start. (This is just one of many ways to accomplish this).
For 2. your approach makes sense. Load the required data on componentWillMount asynchronously.
Furthermore, regarding being "up-to-date" with data: this entirely depends on your application needs. A few ideas to help you get started exploring your problem domain:
With each request to get offers, also send or save a time stamp. Have the application decide when a time stamp is "too old" and request again.
Implement real time communication, for example socket.io which pushes the data to the client instead of the client requesting it.
Request the data at an interval suitable to your application. You could pass along the last time you requested the information and the server could decide if there is new data available or return an empty response in which case you display the existing data.

Store is loaded twice after data.Model.save()

I have a grid with remote data (php/mysql/json) and use a form to insert records or to edit this data.
I use the api configuration of the proxy/store. I use MVC architecture.
So, all very simple (in pseudo code):
get selected model form grid or create model
frm.loadRecord()
frm.updateRecord()
frm.getRecord().save()
and all works fine, but I noticed in the browser console that after the POST (works fine, calls either the url configured with create or the url configured with update), the store calls (GET) the url configured with retrieve twice. These calls are identical.
So functionally all works fine and I could ignore it, but now I've noticed I want it fixed.
Can anyone help me where to look? Thanks in advance.
Details:
It's all really basic:
In the controller of the gridpanel:
updateRow: function (gridpanel) {
var sm = gridpanel.getSelectionModel();
var record = sm.getLastSelected();
this.showForm(record);
}
and
showForm: function (record) {
...
formpanel.show();
var frm = formpanel.getForm();
frm.loadRecord(record);
}
In the controller of the formpanel:
submit: function(frm) {
frm.updateRecord();
frm.getRecord().save();
}
When I remove the save action the GET requests aren't called, so this seems to trigger them.
In the store:
api: {
create: '../php/api/customers.php?request=create',
read: '../php/api/customers.php?request=retrieve&scope=summary',
update: '../php/api/customers.php?request=update',
destroy: '../php/api/customers.php?request=delete'
}
The screenshot:

Is there an equivalent to KnockoutJs' isObservable in AngularJs

I'm running through some samples on Asp.net Web Api 2 and the project I will eventually be working on is going to utilise AngularJs. A couple of the data-binding scenarios I'm working on will have angular's $watch implemented and as I understand it, having the deep flag set to true on this function will notify of new and old values, but not at the property level - only at the array object level. The ultimate goal is to be able to isolate a property change and send this change as a PATCH request to Web Api rather than send the entire object as a PUT request.
The sample I have is currently using knockoutJs and the approach has a model that represents the data where the property values that need to be watched are set as observable(propName). My question is basically whether or not I can convert the following knockoutJs code to something similar in Angular:
self.watchModel = function (model, callback) {
for (var key in model) {
if (model.hasOwnProperty(key) && ko.isObservable(model[key])) {
self.subscribeToProperty(model, key, function (key, val) {
callback(model, key, val);
});
}
}
}
self.subscribeToProperty = function (model, key, callback) {
model[key].subscribe(function (val) {
callback(key, val);
});
}
with the model looking something similar to the following:
var obsEmployee = {
Id: employee.Id,
Name: ko.observable(employee.Name),
Email: ko.observable(employee.Email),
Salary: ko.observable(employee.Salary),
}
I'm sure that there's either an equivalent method available in Angular, or the difference in implementation is significant enough that there is another approach.
There is not. Angular uses dirty checking instead of a subscription/notification framework. Thus, every observed variable is observable. See here for more: http://www.sitepoint.com/understanding-angulars-apply-digest/

Proper server response for Backbone.js

I am implementing Backbone.js with Codeigniter, and having a hard time receiving a proper response from Codeigniter upon a Ajax call. I was doing a #Create, which led to #save, and then #set, right at there, it breaks and couldn't find the ID in the format I returned the data.
For testing purpose, I'm echo-ing
'[{"id":"100"}]'
right back to the browswer, still it couldn't find it.
Anyone aware of a Backbone/Codeigniter(or similar) RESTful implementation example?
You need to return 200 response code or it would not pass as good response.
I built few apps with Backbone/CI combo and it is much easier if you use Phil Sturgeon's REST implementation for CodeIgniter
Than you controller that is located at url example.com/api/user and directory applications/controllers/api/user.php would look something like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
include APPPATH.'core/REST_Controller.php'; // MUST HAVE THIS LINE!!!
class User extends REST_Controller {
// update user
public function index_put() // prefix http verbs with index_
{
$this->load->model('Administration');
if($this->Administration->update_user($this->request->body)){ // MUST USE request->body
$this->response(NULL, 200); // this is how you return response with success code
return;
}
$this->response(NULL, 400); // this is how you return response with error code
}
// create user
public function index_post()
{
$this->load->model('Administration');
$new_id = $this->Administration->add_user($this->request->body);
if($new_id){
$this->response(array('id' => $new_id), 200); // return json to client (you must set json to default response format in app/config/rest.php
return;
}
$this->response(NULL, 400);
}
// deleting user
public function index_delete($id)
{
$this->load->model('Administration');
if($this->Administration->delete_user($id)){
$this->response(NULL, 200);
return;
}
$this->response(NULL, 400);
}
}
It will help you to return proper responses.
TIP: Also whatever you return to client will be set to model attributes. E.g. when creating user if you return only:
'[{"id":"100"}]'
model will be assigned id 100. But if you return:
'[{"id":"100", "date_created":"20-aug-2011", "created_by": "Admin", "random": "lfsdlkfskl"}]'
all this key value pairs will be set to user model (I added this just for clarity, since it confused me in start)
IMPORTANT: this is for CI 2.0+ if you are using 1.7.x REST implementation is a tiny bit different that concerns directory structure

Resources