Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRM-21849: Inline Relationship Type Edit #11853

Merged
3 changes: 0 additions & 3 deletions CRM/Contact/Form/Relationship.php
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,6 @@ public function buildQuickForm() {
// Select list
$relationshipList = CRM_Contact_BAO_Relationship::getContactRelationshipType($this->_contactId, $this->_rtype, $this->_relationshipId);

// Metadata needed on clientside
$this->assign('relationshipData', self::getRelationshipTypeMetadata($relationshipList));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the function getRelationshipTypeMetadata is no longer used then it can be removed. I agree this can all be done from the frontend.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to clean it up to avoid having code that does the same thing in JS and PHP, but it's still used in one other place. My JS skills are very limited, but if you think it's best that we remove this function and provide some common service to fetch this data then I can give that a shot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, didn't realize it was used elsewhere. I don't think that's a priority.


foreach ($this->_allRelationshipNames as $id => $vals) {
if ($vals['name_a_b'] === 'Employee of') {
$this->assign('employmentRelationship', $id);
Expand Down
111 changes: 107 additions & 4 deletions templates/CRM/Contact/Form/Relationship.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,113 @@
CRM.$(function($) {
var
$form = $("form.{/literal}{$form.formClass}{literal}"),
relationshipData = {/literal}{$relationshipData|@json_encode}{literal};
$('[name=relationship_type_id]', $form).change(function() {
$relationshipTypeSelect = $('[name=relationship_type_id]', $form),
relationshipData = {},
contactTypes = {};

$('body').on('crmOptionsEdited', 'a.crm-option-edit-link', refreshRelationshipData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a init function, it would help to organise the code, also place other initialisation code inside.

(function init () {
  $('body').on('crmOptionsEdited', 'a.crm-option-edit-link', refreshRelationshipData);
  refreshRelationshipData().done(...)
  $relationshipTypeSelect.change(function() {
})()


// Initial load and trigger change on select
refreshRelationshipData().done(function() {
$relationshipTypeSelect.change();
});

/**
* Fetch contact types and reset relationship data
*/
function refreshRelationshipData() {
var defer = $.Deferred();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to create defer object, the following will do the same thing

relationshipData = {};

return getContactTypes()
  .then(function() {
    return getRelationshipData();
  });
});


// reset
relationshipData = {};

getContactTypes().then(function() {
getRelationshipData().then(function() {
defer.resolve();
});
});

return defer.promise();
}

/**
* Fetches the relationship data using latest relationship types
*/
function getRelationshipData() {
var subtype,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These variables are used only inside $.each, so we can define them inside only. Overall this is how it should look like

function getRelationshipData() {
  var defer = $.Deferred();

  if (!$.isEmptyObject(relationshipData)) {
    defer.resolve(relationshipData);
  }

  CRM.api3("RelationshipType", "get")
    .done(function (data) {
      $.each(data.values, function (key, relType) {
        // Please add a comment mentioning what is ["a", "b"]
        $.each(["a", "b"], function (index, suffix) {
          var subtype = relType["contact_subtype_" + suffix];
          var type = subtype || relType["contact_type_" + suffix];
          var label = getContactTypeLabel(type) || "Contact";
          var placeholder = "- select " + label.toLowerCase() + " -";
          relType["placeholder_" + suffix] = placeholder;
        });

        relationshipData[relType["id"]] = relType;
      });

      defer.resolve(relationshipData);
    });

  return defer.promise();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, I like the early return!

type,
label,
placeholder,
defer = $.Deferred();

if ($.isEmptyObject(relationshipData)) {
CRM.api3("RelationshipType", "get").done(function (data) {
$.each(data.values, function (key, relType) {
$.each(["a", "b"], function (index, suffix) {
subtype = relType["contact_subtype_" + suffix];
type = subtype || relType["contact_type_" + suffix];
label = getContactTypeLabel(type) || "Contact";
placeholder = "- select " + label.toLowerCase() + " -";
relType["placeholder_" + suffix] = placeholder;
});
relationshipData[relType["id"]] = relType;
});

defer.resolve(relationshipData);
});
} else {
defer.resolve(relationshipData);
}

return defer.promise();
}

/**
* Gets a contact type label based on a provided name
* @param {String} name - the name of the contact type
*/
function getContactTypeLabel(name) {
var label = "";

$.each(contactTypes, function(index, contactType) {
if (contactType.name === name) {
label = contactType.label;
return false;
}
});

return label;
}

/**
* Fetches contact types
*/
function getContactTypes() {
var defer = $.Deferred();
if ($.isEmptyObject(contactTypes)) {
CRM.api3("ContactType", "get").done(function (data) {
contactTypes = data.values;
defer.resolve(contactTypes);
});
} else {
defer.resolve(contactTypes);
}

return defer.promise();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend not loading contact types via ajax because the two back-to-back ajax calls will be unnecessarily slow. I suggest pre-loading contactType data into the dom (via $form->assign()) to avoid the lag.


$relationshipTypeSelect.change(function() {
var $select = $(this);

// ensure we have relationship data before changing anything
getRelationshipData().then(function() {
updateSelect($select);
})
});

function updateSelect($select) {
var
val = $(this).val(),
val = $select.val(),
$contactField = $('#related_contact_id[type=text]', $form);
if (!val && $contactField.length) {
$contactField
Expand Down Expand Up @@ -190,7 +293,7 @@

CRM.buildCustomData('Relationship', rType);
}
}).change();
}
});
{/literal}
</script>
Expand Down