Skip to content

Commit

Permalink
Re-using readonly attribute of md-chips directive.
Browse files Browse the repository at this point in the history
I tried to use them before but they caused some problems as mentioned
in this issue:

angular/material#2841

However, it got fixed in v0.11 as mentioned in this comment:

angular/material#2841 (comment)
  • Loading branch information
rafidka committed Oct 2, 2015
1 parent 5189e8c commit c71dac8
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 75 deletions.
2 changes: 1 addition & 1 deletion HadithHouseWebsite/hadiths/static/hadiths/html/hadith.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ <h1>
</md-input-container>

<label>Person</label>
<hh-person-selector person-id="ctrl.hadith.person" read-only="!ctrl.isEditing"></hh-person-selector>
<hh-person-selector persons-ids="ctrl.hadithPersonsIds" read-only="!ctrl.isEditing" single-select="true"></hh-person-selector>

<label>Tags</label>
<hh-tag-selector tag-names="ctrl.hadith.tags" read-only="!ctrl.isEditing"></hh-tag-selector>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
<span>
<md-chips ng-hide="!ctrl.readOnly" md-autocomplete-snap md-require-match>
<md-chip ng-if="ctrl.person">
{{ ctrl.person.display_name }}
</md-chip>
<md-chips ng-model="ctrl.persons" readonly="ctrl.readOnly"
md-autocomplete-snap
md-require-match="true">
<md-autocomplete
md-selected-item="ctrl.selectedTag"
md-selected-item-change=""
md-search-text="ctrl.personQuery"
md-search-text-change=""
md-items="person in ctrl.findPersons(ctrl.personQuery)"
md-item-text="personName"
placeholder="Search for a person">
<md-item-template>
<span md-highlight-text="ctrl.personQuery">{{ person.display_name || person.full_name }}</span>
</md-item-template>
<md-not-found>
No matches found for "{{ ctrl.personQuery }}".
</md-not-found>
</md-autocomplete>
<md-chip-template>
<span>
<strong>{{$chip}}</strong>
</span>
<span>
<strong>{{ $chip.display_name || $chip.full_name }}</strong>
</span>
</md-chip-template>
</md-chips>
<md-autocomplete
ng-hide="ctrl.readOnly"
md-selected-item="ctrl.person"
md-selected-item-change="ctrl.onPersonChange()"
md-search-text="ctrl.personQuery"
md-search-text-change=""
md-items="person in ctrl.findPersons(ctrl.personQuery)"
md-item-text="person.display_name"
ng-hide="ctrl.readOnly"
placeholder="Search for a person">
<md-item-template>
<span md-highlight-text="ctrl.personQuery">{{ person.display_name }}</span>
</md-item-template>
<md-not-found>
No matches found for "{{ ctrl.personQuery }}".
</md-not-found>
</md-autocomplete>
</span>

Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
<span>
<md-chips ng-model="ctrl.tagNames" md-autocomplete-snap md-require-match>
<md-autocomplete
md-selected-item="ctrl.selectedTag"
md-selected-item-change=""
md-search-text="ctrl.tagQuery"
md-search-text-change=""
md-items="tagName in ctrl.findTagNames(ctrl.tagQuery)"
md-item-text="tagName"
ng-hide="ctrl.readOnly"
placeholder="Search for a tag">
<md-item-template>
<span md-highlight-text="ctrl.tagQuery">{{ tagName }}</span>
</md-item-template>
<md-not-found>
No matches found for "{{ ctrl.tagQuery }}".
</md-not-found>
</md-autocomplete>
<md-chip-template>
<span>
<strong>{{$chip}}</strong>
</span>
</md-chip-template>
<md-icon md-chip-remove class="material-icons" ng-hide="ctrl.readOnly"
style="vertical-align: middle; font-size: 14pt; font-weight: bold;">close
</md-icon>
</md-chips>
<md-chips ng-model="ctrl.tagNames" readonly="ctrl.readOnly"
md-autocomplete-snap
md-require-match="true">
<md-autocomplete
md-selected-item="ctrl.selectedTag"
md-selected-item-change=""
md-search-text="ctrl.tagQuery"
md-search-text-change=""
md-items="tagName in ctrl.findTagNames(ctrl.tagQuery)"
md-item-text="tagName"
placeholder="Search for a tag">
<md-item-template>
<span md-highlight-text="ctrl.tagQuery">{{ tagName }}</span>
</md-item-template>
<md-not-found>
No matches found for "{{ ctrl.tagQuery }}".
</md-not-found>
</md-autocomplete>
<md-chip-template>
<span>
<strong>{{$chip}}</strong>
</span>
</md-chip-template>
</md-chips>
</span>
69 changes: 61 additions & 8 deletions HadithHouseWebsite/hadiths/static/hadiths/js/hadith.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
var HadithHouseApp = angular.module('HadithHouseApp');

HadithHouseApp.controller('HadithCtrl',
function ($mdDialog, $location, $routeParams, $resource, HadithsService, ToastService) {
var Hadith = $resource(getApiUrl() + 'hadiths/:hadithId');

function ($scope, $mdDialog, $location, $routeParams, $resource, HadithsService, ToastService) {
var ctrl = this;

// Make a request to load the hadith.
// Is the user loading an existing hadith or adding a new one?
ctrl.hadithId = $routeParams.hadithId;
if (ctrl.hadithId === 'new') {
// ...adding new hadith.
ctrl.hadith = {
text: '',
person: 1,
Expand All @@ -20,15 +19,44 @@
ctrl.addingNew = true;
ctrl.isEditing = true;
} else {
ctrl.hadith = Hadith.get({hadithId: ctrl.hadithId}, function () {
ctrl = ctrl;
// ...loading an existing hadith.
HadithsService.getHadith(ctrl.hadithId).then(function onSuccess(hadith) {
ctrl.hadith = hadith;
}, function onError() {

});
ctrl.addingNew = false;
ctrl.isEditing = false;
}

ctrl.error = false;

// If the ID of the person changes in the person-selector directive,
// reflect the change to the hadith object.
$scope.$watch(function() { return ctrl.hadithPersonsIds; }, function(newValue, oldValue) {
if (newValue === oldValue || !ctrl.hadith) {
return;
}
if (ctrl.hadithPersonsIds && ctrl.hadithPersonsIds.length > 0) {
ctrl.hadith.person = ctrl.hadithPersonsIds[0];
} else {
ctrl.hadith.person = null;
}
});

// If the ID of the person in the hadith object changes, reflect the change
// to the person-selector directive.
$scope.$watch('ctrl.hadith.person', function(newValue, oldValue) {
if (newValue === oldValue) {
return;
}
if (ctrl.hadith.person !== null) {
ctrl.hadithPersonsIds = [ctrl.hadith.person];
} else {
ctrl.hadithPersonsIds = [];
}
});

var oldHadith = {};

/**
Expand Down Expand Up @@ -59,6 +87,9 @@
ctrl.isEditing = true;
};

/**
* Called by finishEditing() for the case of adding a new hadith.
*/
function addNewHadith() {
// Send the changes to the server.
HadithsService.postHadith(ctrl.hadith).then(function onSuccess(result) {
Expand All @@ -73,6 +104,9 @@
});
}

/**
* Called by finishEditing() for the case of saving an already existing hadith.
*/
function saveCurrentHadith() {
// Send the changes to the server.
HadithsService.putHadith(ctrl.hadith).then(function onSuccess() {
Expand All @@ -81,8 +115,7 @@
ToastService.show("Changes saved.");
}, function onFail() {
// Failed to save the changes. Restore the old data and show a toast.
ctrl.isEditing = false;
restoreCopyOfHadith();
ctrl.cancelEditing();
ToastService.show("Failed to save hadith. Please try again.");
});
}
Expand All @@ -91,18 +124,38 @@
* Called when the user clicks on the save icon to save the changes made.
*/
ctrl.finishEditing = function() {
if (!ctrl.validateHadith()) {
return;
}
if (ctrl.addingNew) {
addNewHadith();
} else {
saveCurrentHadith();
}
};

/**
* Validates that the data the user put is valid; otherwise, show a toast.
* @returns {boolean} True or false.
*/
ctrl.validateHadith = function() {
if (ctrl.hadith.person == null) {
ToastService.show("Please choose a person.");
return false;
}
if (ctrl.hadith.tags.length === 0) {
ToastService.show("Please choose at least one tag.");
return false;
}
return true;
}

/**
* Called when the user clicks on the X icon to cancel the changes made.
*/
ctrl.cancelEditing = function() {
ctrl.isEditing = false;
restoreCopyOfHadith();
};
});
}());
Original file line number Diff line number Diff line change
Expand Up @@ -39,34 +39,60 @@ function waitForPromises(promises, callback) {
ctrl.availPersons = [];
ctrl.availPersonsLoaded = false;

if (!ctrl.personId) {
ctrl.personId = null;
if (!ctrl.personsIds) {
ctrl.personsIds = [];
}

if (!ctrl.persons) {
ctrl.persons = [];
}

PersonsService.getPersons().then(function onSuccess(persons) {
ctrl.availPersonsLoaded = true;
ctrl.availPersons = persons;
});

$scope.$watch(function() { return ctrl.personId; }, function() {
if ((!ctrl.person || ctrl.person.id != ctrl.personId) && ctrl.personId !== null) {
PersonsService.getPerson(ctrl.personId).then(function(person) {
ctrl.person = person;
function onPersonsIdsChanged(newValue, oldValue) {
if (newValue && oldValue && newValue.toString() === oldValue.toString()) {
return;
}
PersonsService.getPersons().then(function() {
ctrl.persons = ctrl.personsIds.map(function (id) {
return PersonsService.getPersonSync(id);
});
});
}

$scope.$watch(function() { return ctrl.personsIds; }, onPersonsIdsChanged);
$scope.$watchCollection(function() { return ctrl.personsIds; }, onPersonsIdsChanged);

function onPersonsChanged(newValue, oldValue) {
if (ctrl.persons) {
// If the control only allows single select, we remove every elements
// before the last.
if (ctrl.singleSelect === true && ctrl.persons.length > 1) {
ctrl.persons.splice(0, ctrl.persons.length - 1);
}
ctrl.personsIds = ctrl.persons.map(function(person) {
return person.id;
});
}
});
ctrl.onPersonChange = function() {
}

$scope.$watch(function() { return ctrl.persons; }, onPersonsChanged);
$scope.$watchCollection(function() { return ctrl.persons; }, onPersonsChanged);

/*ctrl.onPersonChange = function() {
ctrl.personId = ctrl.person.id;
};
};*/

ctrl.findPersons = function (query) {
if (!ctrl.availPersonsLoaded) {
return [];
}

return ctrl.availPersons.filter(function (person) {
return /*ctrl.personId.indexOf(person.id) == -1 &&*/ (
person.title.indexOf(query) > -1 ||
return (person.title.indexOf(query) > -1 ||
person.display_name.indexOf(query) > -1 ||
person.full_name.indexOf(query) > -1 ||
person.brief_desc.indexOf(query) > -1);
Expand All @@ -83,8 +109,9 @@ function waitForPromises(promises, callback) {
controllerAs: 'ctrl',
bindToController: true,
scope: {
personId: '=',
readOnly: '='
personsIds: '=',
readOnly: '=',
singleSelect: '='
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
HadithHouseApp.controller('TagSelectorCtrl', function ($scope, TagsService) {
var ctrl = this;

ctrl.singleSelect = false;

if (!ctrl.tagNames) {
ctrl.tagNames = [];
}
Expand All @@ -39,6 +41,12 @@
ctrl.availTagNames = tags.map(function(tag) { return tag.name; });
});

$scope.$watchCollection(function() { return ctrl.tagNames; }, function() {
if (ctrl.singleSelect === true && ctrl.tagNames && ctrl.tagNames.length > 1) {
ctrl.tagNames.splice(0, ctrl.tagNames.length - 1);
}
});

ctrl.findTagNames = function (query) {
if (!ctrl.availTagsLoaded) {
return [];
Expand All @@ -60,7 +68,8 @@
bindToController: true,
scope: {
tagNames: '=',
readOnly: '='
readOnly: '=',
singleSelect: '='
}
};

Expand Down
4 changes: 2 additions & 2 deletions HadithHouseWebsite/hadiths/templates/hadiths/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/0.10.0/angular-material.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/0.10.0/angular-material.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/0.11.0/angular-material.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/0.11.0/angular-material.min.css">
<script
src="https://cdnjs.cloudflare.com/ajax/libs/angular-material-icons/0.5.0/angular-material-icons.min.js"></script>

Expand Down

0 comments on commit c71dac8

Please sign in to comment.