How to access nested items in Algolia instantsearch.js - algolia

In Algolia, I have the following data structure
In my instantsearch.js template how do I reference File > ID?
This is the template I have, but anything that is nested comes back as blank. Top-level items (such as Title) are returned fine.:
search.addWidget(
instantsearch.widgets.infiniteHits({
container: '#SearchServiceHitsContainer',
templates: {
empty: 'No results',
item: '<li class="content-search-results-item highlight"> \
<a href="/Content/ViewContent?file={{{File.ID}}}" target="_blank" class="content-search-results-item-trigger track-event" download title="{{Title}}" data-item-action="Download File" data-item-id="{{{File.ID}}}" data-item-title="{{Title}}" data-user-id="' + userID + '"> \
<div class="image-container"> \
<img data-original="/Content/ViewContent?file={{{Thumbnail.ID}}}&log=false" class="lazy" /><br /> \
</div> \
<span class="content-search-results-item-title">{{Title}}</span> \
</a> \
</li>'
},
hitsPerPage: 10
})
);

Maybe check if the index parameter "attributesToRetrieve" is configured in a way that disable some attributes from being retrieved when displaying your search with Algolia: https://www.algolia.com/doc/api-client/javascript/parameters/attributesToRetrieve/

Related

Angular2 Form-validation with prefilled data

I have a form with two input fields (text). Creating from scratch (= no information) works great. As you can guess, maybe I want to change the values later.
The problem: When only changing the description for example (and leaving the title as is from the server), the title will be invalid. If I change the last char (Testproject to Testproject2) for example it works. What do I have to change?
Template:
<form [formGroup]="projectEditForm" novalidate>
<div [formGroup]="projectEditForm">
<label>Title</label>
<input type="text" [class.validationError]="projectEditForm.controls.Title.invalid && (projectEditForm.controls.Title.dirty || submitted)"
value="{{ (project | async)?.ProjectName }}" formControlName="Title">
<label>Description</label>
<textarea [class.validationError]="projectEditForm.controls.Description.invalid && (projectEditForm.controls.Description.dirty || submitted)"
value="{{ (project | async)?.Description }}" formControlName="Description"></textarea>
</div>
</form>
Form model:
this.projectEditForm = this._fb.group({
Title: ['', [<any>Validators.required, <any>Validators.minLength(5)]],
Description: ['', [<any>Validators.required]]
});
Your problem comes from the fact that you are not using the FormControl correctly. You should not bind to the value attribute of the input tag because it's FormControl's job.
When binding to the value attribute, you are writing to the dom without notifying the FormControl that something has changed.
You should set the value dynamically using the FormControl instead. When you receive the data from http, you just need to call this :
this.projectEditForm.get("controlName").setValue(randomValueFromSomewhere);
in your template (note that I removed the classes to be more concise):
<div [formGroup]="projectEditForm">
<label>Title</label>
<input type="text" formControlName="Title">
<label>Description</label>
<textarea formControlName="Description"></textarea>
</div>
Your condition for the title input class is invalid
[class.validationError]="projectEditForm.controls.Name.invalid && (projectEditForm.controls.Description.dirty || submitted)"
It should be :
[class.validationError]="projectEditForm.controls.Title.invalid && (projectEditForm.controls.Title.dirty || submitted)"
Try to init the form group on http call success and then:
this.projectEditForm = this._fb.group({
Title: [project.ProjectName, [<any>Validators.required, <any>Validators.minLength(5)]],
Description: [project.Description, [<any>Validators.required]]
});

Using same form for insert and edit

How can I use the same form for inserting and editing a document in Meteor.
For insert I use empty form without variable:
<template name="frmOrganization">
// no doc variable
<form class="form-horizontal" role="form">
...
<input type="text" class="form-control" id="Name">
And for update I use form with variable:
<template name="frmOrganization">
{{#with organization}} // doc variable
<form class="form-horizontal" role="form">
...
<input type="text" class="form-control" id="Name" value="{{Name}}">
(Using Meteor 0.9.3 + Iron-Router)
I had the same issue and the workaround I used was as follows (seems to be more of a hack but I get to avoid having multiple forms)
<template name="frmOrganization">
// no doc variable
<form class="form-horizontal" role="form">
...
<input type="text" class="form-control" id="Name" value={{name}}>
{{#if name}}
<input type="submit" value="Edit"/>
<input type="submit" value="Delete"/>
{{else}}
<input type="submit" value="Add"/>
{{/if}}
...
In my router.js file
this.route('frmOrganization', {
path: '/organisation/:_id/edit',
data: function() { return Organisation.findOne(this.params._id); }
});
All seems pretty standard, but then for my Add link, I use:
Add
Which will create he following link:
/organisation/null/edit
The null page gives you your Add page and an ID would give you your edit page.
-- Meteor Noob
A simple way would be to use an upsert with the _id of the organization document as the first argument. If nothing is found in the collection when you try to upsert, then it will insert the data into a new document (second argument).
However, there are some packages which can make this task much easier:
autoform, simple-schema and collection2
(I would link to the others but lack the reputation)
Firstly define a schema and apply it to the collection as follows:
Pages = new Meteor.Collection('pages');
PagesSchema = new SimpleSchema({
title: {
type: String,
label: 'Title',
max: 100
},
body: {
type: String,
label: 'Body',
max: 1000
}
});
Pages.attachSchema(PagesSchema);
Then it's possible to simply switch these two templates for an insert or update:
{{> quickForm collection="Pages" id="page-form" type="insert"}}
{{> quickForm collection="Pages" doc=page id="page-form" type="update"}}
(With 'page' being the document itself available in the template)
These handlebars helpers will produce the entire form, and you can even validate with them.
Say that you have a create form at path /my-form. This is fairly straightforward. It creates a new document in your database with an :_id of, say, XYZ123.
Now you want an edit form.
You create a link that goes to /my-form/XYZ123
You've created a path with the document :_id as a parameter.
You then set your route to read the :_id parameter of your path as data. (Look at the Discover Meteor book for an example)
Now add code to your existing form that will take that :_id from the path, do a lookup for the document, and pre-populate the values in the form with the values it finds from the database based off of that :_id.
And change the submit button to do an update instead of insert.
As for delete, that's simple. No extra form needed. On the edit form just create a big red delete button that will delete the document with that :_id.
Write your JS so that if there is a parameter in the path, make the delete button visible and turn the submit button from insert into update.

About the $dirty property and getting only modified fields in a form

I have a form with few fields and I'm trying to get modified fields only.
Here is what I got so far (simplified version) :
<form name="formTicket">
<div class="item title">
<label for="category-assignation"><?php echo T::_("Assignation :")?></label>
<textarea type="text" name="assignation" cols="50" rows="4" id="category-assignation" data-ng-model="ticket.assignation"></textarea>
</div>
<div class="item title">
<input id="save" type="submit" value="Save" data-ng-click="saveTicketInfo()" />
</div>
</form>
In my controller.js, I have :
$scope.saveTicketInfo = function() {
console.info($scope.ticket);
console.info($scope.formTicket);
//Query to my service to save the data
Category.saveInfo.query({data: $scope.ticket});
};
Prior to AngularJs, I would save my fields in an array at the loading of my form and compare their values with the new values posted. I could still do this but I'm looking for an AngularJs approach.
I've been trying to use the $dirty property of each field and only send to my services those with "true" value but this behavior is not suitable for me : if the defaut value for my field is "test" and the user modify the input to "test2" and modify it back to "test" and post it, $dirty will be true (even if the value has not really changed).
Is there any convenient and optimal way to achieve what I want ?
Thank you for your time.

How to edit data when combining angularjs and mongodb

I'm a beginner in the AngularJs and MongoDb world (i started learning today!!)
Actually i'm trying to do something very basic : Display a list of record, with an add button and a edit link with each record.
I'm using this lib https://github.com/pkozlowski-opensource/angularjs-mongolab to connect to mongoweb.
Actually my data is displayed, when i try to add a record it works, but the problem is when i try to display the edit form!
Here is my index.html file, in which i display the data with a form to add a record and with the edit links :
<div ng-controller="AppCtrl">
<ul>
<li ng-repeat="team in teams">
{{team.name}}
{{team.description}}
edit
</li>
</ul>
<form ng-submit="addTeam()">
<input type="text" ng-model="team.name" size="30" placeholder="add new team here">
<input type="text" ng-model="team.description" size="30" placeholder="add new team here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
And here is my edit.html code, which displays an edit form :
<div ng-controller="EditCtrl">
<form ng-submit="editTeam()">
<input type="text" name="name" ng-model="team.name" size="30" placeholder="edit team here">
<input type="text" name="description" ng-model="team.description" size="30" placeholder="edit team here">
<input class="btn-primary" type="submit" value="validate edit">
</form>
</div>
And finally my js code:
var app = angular.module('app', ['mongolabResource']);
app.constant('API_KEY', '____________________________');
app.constant('DB_NAME', 'groups');
app.factory('Teams', function ($mongolabResource) {
return $mongolabResource('teams');
});
app.controller('AppCtrl', function ($scope, Teams) {
$scope.teams = Teams.query();
$scope.addTeam = function() {
varteam = {
name: $scope.team.name,
description: $scope.team.description
};
$scope.teams.push(varteam);
Teams.save($scope.team);
$scope.team.name = '';
$scope.team.description = '';
};
});
app.controller('EditCtrl', function ($scope, Teams) {
//????????
});
My AppCtrl works perfecty, it displays the data w add records perfectly.
Now i want to add the js code for the edit, but i don't even know form where to start ? how do i a get the id parameter in the url ? how do i tell the view to fill out the form fields from the values from the database ? And finally how do i update the databse.
I know that i asked a lot of question but i'm really lost! thank you
There are of course many possible solutions.
One solution is to use angularjs routing. See http://docs.angularjs.org/tutorial/step_07 for a tutorial.
Basically replace your ul list with something like:
<ul>
<li ng-repeat="team in teams">
{{team.name}}
{{team.description}}
edit
</li>
</ul>
Then you can create a route that responde to your url:
yourApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/teams', {
templateUrl: 'partials/team-list.html',
controller: 'TeamListCtrl'
}).
when('/teams/:teamId', {
templateUrl: 'partials/team-detail.html',
controller: 'TeamDetailCtrl'
}).
otherwise({
redirectTo: '/teams'
});
}]);
In this way from the detail controller (that will replace your EditCtrl) you can access the id parameter using: $routeParams.teamId
Anyway I suggest to study well all the tutorials for a better overview.

coffeescript focus is not setting on my field

I want to make client side validation in my project.
Here the requirement is, if the user submitted blank form or he did not field any one input field, then normal html list should have to generate.
Under that list, the all input fields should have to come who has error.
Not only the input field, but it should be the link of that input field.
Once the links came in that list, then user should be able to click on that link. after clicking on that link, then his focus should have to set on the text field.
Here I could create link properly, but I can’t set the focus.
So here my coffeescript:
$(document).ready ->
# first fetch all input field who have errors.
errorElements = $('.content').find('.help-inline').prev()
ul = $('<ul id="errorlist"></ul>')
errorElements.each (i) ->
span = $(this).next()
labelText = $(this).parent().parent().find('label')
$(' <li> <a href="#' + $(this).attr('id') + '" class="errorlink" >' + labelText.text() + ' ' + '(' + span.text() + ')' + '</a></li>').appendTo(ul)
$('#errorcontainer').html(ul)
$(".errorlink").bind "click", (e) ->
# first I am checking it is binding or not.
alert('hello')
$(this).attr(‘href’).setFocus()
I am using simple_form for my html.
So it is generating html for me like this:
<div class=' content '>
<form accept-charset="
UTF-8
" action="
/levels/basic-computer/topics" class="
simple_form form-horizontal
" enctype="
multipart/form-data
" id="
new_topic " method=" post " novalidate=" novalidate ">
<div style=" margin:0;padding:0;display:inline ">
<div class=' form-inputs'>
<div class=" control-group string required topic_title error ">
<label class=" string required control-label " for=" topic_title ">
<abbr title=" required ">
*
</abbr>
Title
</label>
<div class=" controls ">
<input class=" string required " id=" topic_title " name=" topic[title] " size=" 50 " type=" text " value="" />
<span class=" help-inline ">
can't be blank
</span>
</div>
</div>
What I am wrong here?
I was under the impression that just using .focus() on the jQuery object would be sufficient.
jQuery API Docs: Focus
So in theory as long as this is the correctly selected element you only need to do this:
$(this).focus()
Also I notice that you're bind code is outdented from the $(document).ready block.
Another tip in coffeescript $ -> is shorthand for $(document).ready...
For example
$ ->
# do something after the document is ready